为什么这个循环每次重复两次?
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);
具体来说,有两点不明白。
- 为什么
i
不是每次迭代都增加?
then = await { then };
到底是做什么的?我的第一个猜测是它会等待对 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 并且没有什么可真正等待的:
- 一个人会 运行 直到它达到
await
然后将被暂停。
- 另一个会 运行 直到它达到
await
然后将被暂停。
- 重复 1. 和 2. 直到没有等待。
下面的函数将每个数字打印两次。有人可以解释它是如何工作的吗?我试过调试,但我只能看到 i
的值只会在每两次迭代时增加。
async function run(then) {
for (let i = 1; i <= 10; i++) {
console.log(i);
then = await { then };
}
}
run(run);
具体来说,有两点不明白。
- 为什么
i
不是每次迭代都增加? then = await { then };
到底是做什么的?我的第一个猜测是它会等待对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 并且没有什么可真正等待的:
- 一个人会 运行 直到它达到
await
然后将被暂停。 - 另一个会 运行 直到它达到
await
然后将被暂停。 - 重复 1. 和 2. 直到没有等待。