为什么这个循环每次重复两次?

Why does this loop repeat each iteration twice?

下面的函数将每个数字打印两次。有人可以解释它是如何工作的吗?我试过调试,但我只能看到 i 的值只会在每两次迭代时增加。

async function run(then) {
    for (let i = 1; i <= 10; i++) {
        console.log(i);
        then = await { then };
    }
}

run(run);

具体来说,有两点不明白。

我们可以通过较小的 re-write 包括日志记录来使这一点更清楚:

async function run(callback) {
    let then = callback;
    for (let i = 1; i <= 10; i++) {
        console.log(callback === run ? "A" : "B", i);
        then = await { then };
    }
}

run(run);
.as-console-wrapper { max-height: 100% !important; }

这表明实际上启动了 两个 循环。为简单起见,仅称为 A 和 B。它们记录 await,这意味着它们的记录交错并导致 A 1、B 1、A 2、B 2 等

这是因为第一个语句:run(run)。它将与回调相同的函数传递给自己。这不会 调用 回调,但这是解决这个问题的第一步。


了解正在发生的事情的下一步是 await。您可以 await 任何值,并且在 大多数情况下 如果它不是承诺,则没有关系。如果您有 await 42; 它只是假装值为 Promise.resolve(42) 并在下一个价格变动时立即继续操作。 most non-promises 也是如此。唯一的例外是 thenables - 具有 .then() 方法的对象。

当一个 thenable 被等待时,它的 then() 方法被调用:

const thenable = {
  then() {
    console.log("called");
  }
};

(async () => {
  await thenable;
})()

然后解释 await { then } 语句。这将 shorthand 用于 { then: then },其中 then 是传递给 run 的回调。因此,它创建了一个 thenable 对象,该对象在等待时将执行回调。

这意味着第一次执行 run() 并且在循环 A 的第一次迭代中代码实际上是 await { then: run } 它将再次执行 run 然后开始循环 B .

then 的值每次都被覆盖,因此为什么它只 运行 两个并行循环,而不是更多。


还有更多与完全掌握此代码相关的功能。我展示了一个简单的,之前只是展示等待它调用该方法。然而,实际上 await thenable 将使用两个参数调用 .then() - 可以调用成功和失败的函数。与 Promise 构造函数执行此操作的方式相同。

const badThenable = {
  then() {
    console.log("bad called");
  }
};

(async () => {
  await badThenable;
  console.log("never reached");
})();

const goodThenable = {
  then(resolve, reject) { //two callbacks
    console.log("good called");
    resolve(); //at least one needs to be called
  }
};

(async () => {
  await goodThenable;
  console.log("correctly reached");
})();

这是相关的,因为 run() 需要一个回调,当 await { then: run } 执行时它调用 run(builtInResolveFunction) 然后传递给下一个 await { then: builtInResolveFunction } 进而解决 causes a await 解决。


抛开所有这些,交错日志记录只是任务解决方式的一个因素:

(async () => {
  for (let i = 1; i <= 10; i++){
    console.log("A", i);
    await Promise.resolve("just to force a minimal wait");
  } 
})();

(async () => {
  for (let i = 1; i <= 10; i++) {
    console.log("B", i);
    await Promise.resolve("just to force a minimal wait");
  } 
})();

如果有两个异步函数 运行ning 并且没有什么可真正等待的:

  1. 一个人会 运行 直到它达到 await 然后将被暂停。
  2. 另一个会 运行 直到它达到 await 然后将被暂停。
  3. 重复 1. 和 2. 直到没有等待。