1

TL;DR : 已经解决的 Promise会setImmediate比赛中获胜吗?

背景:

有时你想知道一个 Promise 是否在没有等待它完成的情况下被解决。有一些旧的遗留技巧,例如util.inspect用于获取内部状态并检查它是否包含字符串"<pending>"。但是,更稳定的解决方案是使用Promise.race()(非常小的)超时基本上等待您的未知承诺。

const p = doSomething();

const result = await Promise.race([
    p, 
    new Promise(resolve => setTimeout(resolve, 1))
]);

if (result) {
   // p was resolved within 1 ms!
   ...
}

这将最多等待 1 毫秒来获取result,然后它将包含p或的解析值undefined。如果需要,“超时承诺”当然可能返回不同于undefined区分实际undefined返回值的内容doSomething()

const PENDING = Symbol.for('PENDING');
const result = await Promise.race([
    p, 
    new Promise(resolve => setTimeout(() => resolve(PENDING), 1))
]);

if (result !== PENDING) {
  ...
}

现在我们要么得到解析的值,要么得到doSomething()唯一的符号PENDING

现在我的问题。除了 之外setTimeout,还有一个setImmediate功能基本上就像一个立即到期的计时器;它只是在解决之前给事件循环一个机会。在我Promise.race上面的表达式中使用它时,凭经验它似乎有效,即,如果p已经解决它会setImmediate在比赛中获胜,但我想知道是否有任何这样的保证- 或者我是否应该使用 1 ms 的计时器保证一个已解决的承诺胜过计时器?

我已经尝试在数组中的承诺传递给p之前和之后放置它并且它以两种方式工作,但我仍然担心它可能会随机运行或依赖于操作系统?或者等待一轮 I/O 是否足以保证任何已解决的 Promise 都会获胜?setImmediatePromise.racesetImmediate

文档中:

在 I/O 事件的回调之后安排回调的“立即”执行

编辑:

我发现即使这个“似乎”也有效:

const result = await Promise.race([p, new Promise(resolve => resolve(PENDING))]);

甚至是这个:

const result = await Promise.race([p, Promise.resolve(PENDING)]);

但是,这里的顺序很重要。如果p已解决并且在超时承诺之前,它将获胜,但如果它在数组中的超时承诺之后,它将失败。p但问题是一样的:如果已经解决,这种方法是否保证让胜利?

4

1 回答 1

1

考虑 Nodejs 中的以下代码

参考。https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

setImmediate(() => console.log("setImmediate"));
setTimeout(() => console.log("setTimeout"));
process.nextTick(() => console.log("nextTick"));
Promise.resolve().then(() => console.log("Promise"));
console.log("sync");

输出:

您可以注意到顺序,这就是它按顺序执行的方式。

sync
nextTick
Promise
setTimeout
setImmediate

为了回答您的问题,我们可以将代码包装在 Promises 中,如下所示:

(async function main() {
  const result = await Promise.race([
    new Promise(resolve => resolve("sync")),
    new Promise(resolve => setImmediate(() => resolve("setImmediate"))),
    new Promise(resolve => setTimeout(() => resolve("setTimeout"))),
    new Promise(resolve => Promise.resolve().then(() => resolve("Promise"))),
    new Promise(resolve => process.nextTick(() => resolve("nextTick"))),
  ]);
  console.log({ result });
})();

由于同步函数是先执行的,所以它会被返回。

输出:

{ result: 'sync' }

您可以评论上面的 Promise 之一,看看哪个先解决。

于 2021-10-06T11:22:53.597 回答