首页 > 解决方案 > 对某些回调具有优先级的 Promise 回调队列

问题描述

我的代码需要同时执行大量异步操作,并以特定的顺序方式处理它们的承诺。

我所说的“特定顺序方式”的意思==>假设您正在按顺序启动 promises promise1, promise2,promise3并且 promise3 实际上首先解决,然后 promise2 其次,然后我想要的是 process promise3promise2并按promise1顺序

让我们考虑一个timeout异步函数,它在 X 秒后超时,并且fetchMyItem1, fetchMyItem2,它返回承诺,当履行时,应该根据是否timeout已解决执行不同的代码。

对于一个具体的场景,假设有一位顾客在柜台等待一件物品送达,或者顾客留下来,我们可以一次拿一件物品直接在柜台为他服务,或者顾客离开 ( timeout)我们必须请服务员来,以便在物品到达时,他/她可以将物品带给他。请注意,即使一件商品正在交付,其他​​商品也应该仍在交付中(承诺待定),甚至可能在为客户提供一件商品或服务器到达时到达(履行)。

这是一些开始的代码

const allItemsToBeDeliveredPromises = [fetchMyItem1(), fetchMyItem2(), ...]
const customerLeavesCounterPromise = timeout()

const waiter = undefined

const allPromisesToBeFulfilled = [...allItemsToBeDeliveredPromises, customerLeavesCounterPromise]

// LOOP
const itemDeliveredOrVisitorLeft = await Promise.all(allPromisesToBeFulfilled)

if hasCustomerLeft(itemDeliveredOrCustomerLeft) {
  // hasCustomerLeft allows us to detect if the promise that resolved first is `customerLeavesCounterPromise` or not
  waiter = await callWaiter()
} else {
  // An item has arrived
  if (waiter) {
    deliverItemViaWaiter(itemDeliveredOrVisitorLeft)
  } else {
    deliverItemAtCounter(itemDeliveredOrVisitorLeft)
  }
}
// remove itemDeliveredOrCustomerLeft from allPromisesToBeFulfilled

// END loop

我不确定如何为这种情况实现循环。Promise 必须在解析时累积到队列中,但队列中的特定 Promise 有优先级(超时 Promise 应在到达时尽快执行,但在完成当前 Promise 的处理后,如果 Promise 已经实现正在处理)

标签: javascriptnode.jspromisepriority-queue

解决方案


其中之一必须具有这样的效果,即,无论何时实现,它都应该改变对尚未处理或尚未处理的其他已履行承诺的处理。

你一起运行它们吗?就像是:

promise1 = asyncFunc1()
promise2 = asyncFunc2()
promise3 = asyncFunc3()

Promise.all([promise1, promise2, promise3]).then(//sometthing)

如果是,则无法完成,除非 promise2 函数和 promise3 函数不等待事件、锁或由 promise1 函数处理的东西。

如果是这种情况,最好组织如下承诺:

asyncFunc1()
    .then(() => asyncFunc2(paramIfOk))
    .catch(() => asyncFunc2(paramIfFail))

在您的示例中:

const allItemsToBeDelivered = [myPromise1(), myPromise2(), ...]

myPromise1() 代码应该等待项目交付检查是否有人在等待它。这是一个模型/代码设计问题,而不是一个承诺问题。

另一种方法是考虑一些事件驱动的逻辑:实体 Customer 有一个已交付事件的侦听器,该事件将在自身解决之前由 waitItemDelivered() 承诺触发。

编辑:按照这里的要求,对事件驱动的解决方案进行更多详细说明。

简短的回答:这在很大程度上取决于您的软件设计。

它已经发布并在生产中运行?小心这样的变化。如果它是您正在开发的服务,您仍然可以及时考虑一些逻辑更改。不会从根本上改变工作方式但使用事件的解决方案并不是那么好,混合模式永远不会得到长期回报。

例子:

const events = require('events');

class Customer() {

    constructor(shop) {
        this.emitter = new events.EventEmitter()

        this.shopEventListener = shop.emitter
        this.setupEventLinstening() // for keeping things clean in the constructor

        // other properties here
    }

    setupEventLinstening() {
        this.shopEventListener.on('product-delivered', (eventData) => {
            // some logic
        })
    }

    buyProduct() {
        // some logic

        this.emitter.emit('waiting-delivery', eventData)
    }
}

class Shop() {

    constructor(shop) {
        this.emitter = new events.EventEmitter()

        // other properties here
    }

    addCustomer(customer) {
        customer.emitter.on('waiting-delivery', (eventData) => {
            // some logic

            self.waitDelivery().then(() => self.emitter.emit('product-delivered'))
        })
    }

    waitDelivery() {
        return new Promise((resolve, reject) => {
            // some logic

            resolve()
        })
    }
}

// setup
const shop = new Shop()
const customer = new Customer(shop)
shop.addCustomer(customer)

这是一种查看逻辑的新方法,但可以在 Promise 中使用类似的方法:

const waitDelivery = () => new Promise((resolve, reject) => {
    logisticWaitDelivery().then(() => {
        someEmitter.emit('item-delivered')
        resolve()
    })
}

const customerPromise = () => new Promise((resolve, reject) => {
    someListener.on('item-delivered', () => {
        resolve()
    })
}

promiseAll([waitDelivery, customerPromise])

推荐阅读