下面的函数将每个数字打印两次.有人能解释一下它是怎么工作的吗?我try 了调试,但我看到的是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的嵌套异步调用完成,然后才会进入下一个迭代,但情况似乎并非如此.

推荐答案

通过略微重写以包括日志(log)记录,我们可以使这一点变得更清楚:

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; }

这表明实际上有two个循环开始了.为了简单起见,我们称之为A和B.它们记录和await,这意味着它们的日志(log)交错并导致A 1、B 1、A 2、B 2等.

这是因为第一个语句:run(run).它将相同的函数作为回调传递给自身.这不是call次回调,但这是解决这一问题的第一步.


理解正在发生的事情的下一步是await.你可以await任何值,如果most cases不是一个promise ,那也无关紧要.如果您有await 42;,它只是假设值是Promise.resolve(42),并立即从下一个刻度继续操作.most个不promise 的情况也是如此.唯一的例外是thenables个对象,它们有.then()个方法.

当等待thenable时,调用其then()方法:

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

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

这就解释了await { then }的说法.它使用{ 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),然后该run(builtInResolveFunction)被传递到下一个await { then: builtInResolveFunction },该下一个await { then: builtInResolveFunction }接着进行解析,从而导致A await进行解析.


撇开所有这些不谈,交错日志(log)记录只是任务解析方式的一个因素:

(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");
  } 
})();

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

  1. 其中一个将运行到await分,然后将被暂停.
  2. 另一个将运行到await分,然后将被暂停.
  3. 重复1.和2.直到没有更多的等待.

Javascript相关问答推荐

为什么(1 + Number.Min_UTE)等于1?

Express.js:以块形式发送响应

在JavaScript中,如何将请求的回调函数的结果合并到运行的代码中?

强制执行useStatego struct 化变量[foo,setFoo]的命名约定?

React Hooks中useState的同步问题

如何使用Echart 5.5.0创建箱形图

没有输出到带有chrome.Devtools扩展的控制台

jQuery提交按钮重新加载页面,即使在WordPress中使用preventDefault()

TypeScript索引签名模板限制

为什么这个JS模块在TypeScript中使用默认属性导入?""

当试图显示小部件时,使用者会出现JavaScript错误.

在使用HighChats时如何避免Datatables重新初始化错误?

如何在ASP.NET中使用Google Charts API JavaScript将条形图标签显示为绝对值而不是负值

如何强制Sphinx中的自定义js/css文件始终加载更改而不缓存?

以编程方式聚焦的链接将被聚焦,但样式不适用

如何在和IF语句中使用||和&;&;?

MongoDB中的嵌套搜索

MongoDB通过数字或字符串过滤列表

如何在独立的Angular 应用程序中添加Lucide-Angel?

TypeORM QueryBuilder限制联接到一条记录