异步是否会使其中的所有内容异步化?

时间:2018-07-06 01:07:57

标签: javascript node.js async-await

根据MDN,

  

异步函数声明定义了异步函数

我理解它,因为该功能将被视为异步过程,就像setTimeout或某些数据库请求一样。例如,在下面的示例中,该过程应在数字之间的某个位置输出“ main”。

let func2 = async () => {
   for (let i = 0; i < 51; i ++) {
       console.log(i);
   }
}

(async () => {
    func2();
    console.log("main");
})()

但是,就像整个过程是同步的一样,“ main”总是在最后被控制台。我理解错了什么?

如果同步代码仍处于同步状态,async的目的是什么?仅允许其中的await并提供某种奇特的方式来返回Promise

2 个答案:

答案 0 :(得分:4)

  

异步是否使其中的所有内容都是异步的?

不。它不是。函数中的代码仍将同步运行,并在运行时阻止事件循环。

  

如果同步代码仍处于同步状态,异步的目的是什么?只允许在其中等待并提供一些幻想的方式来返回Promise?

是的,它主要用于await

但是,在某些情况下,它会自动用承诺包装代码,这一点很有用。例如,它会自动捕获所有抛出的异常,并将其转变为被拒绝的承诺。有时这很有用。有关其他用途的示例,请参见本文的“错误处理”部分:6 Reasons Why JavaScript’s Async/Await Blows Promises Away

但是,async关键字的主要功能是定义一个可以使用await的功能。这就是ES7的设计者决定使await工作的方式。

仅供参考,如果函数中有一个await在等待一个诺言,那么这将导致该函数在await的某个点早返回。它将在那时返回并返回承诺。您正在等待的操作将已经开始,并且直到解决了等待的诺言之后,该功能的其余部分才会执行。因此,使用await会使某些代码稍后执行。但是,与await之前的代码一样,即使函数在await解决之后恢复运行,该函数中的Javascript仍将保持同步和阻塞状态(直到另一个await或直到return)。

将其包装在Promise中并检测何时使用.then()会在调用.then()处理程序时推迟到事件循环的下一个滴答声为止。因此,.then()会稍有延迟,因为您将其包装在promise中,然后使用了.then(),但是代码运行的时间不变。它仍然是同步和阻塞的。

在Javascript中,获取同步代码并使之异步的唯一方法是:

  1. 在另一个进程中运行,并使用进程间通信来传达结果。

  2. 在使用本机线程或某些其他OS异步接口来执行实际工作的本机代码插件中重写代码,然后从您的插件中为Javascript提供异步接口。 on(通常是一个返回承诺或通过回调通知完成的接口)。现在这是诸如fs.readFile()之类的node.js异步功能。他们有一个本机代码实现,该实现立即返回,然后在实现中使用本机线程并通过回调通知完成。

  3. 使用一些node.js插件为您完成一些任务。有些插件旨在提供线程。

  4. 在节点版本10.5 + 中使用node.js线程,并根据其要求进行限制。这是有关该主题的文章:Threads in Node 10.5.0: a practical intro

答案 1 :(得分:4)

否,异步函数内的主体在调用时会运行,但会暂停await表达式。如果await没什么可做的,则该函数将像普通函数一样运行,不同之处在于它返回了promise。

但是,如果有await,执行将暂停并且事件循环将继续。当前事件循环结束后的某个时间里,当等待的约定解决时,它将在中断的地方继续进行。例如,比较此处记录“主”的时间与您的示例。

let func2 = async () => {
    console.log("Start")
    for (let i = 0; i < 10; i ++) {
        if(i == 5) {
            await new Promise(resolve => setTimeout(resolve, 200))
        }
        console.log(i);
    }
 }
 
 (async () => {
     func2().then(() => console.log('done'));
     console.log("main");
 })()

考虑async函数的另一种方法是考虑它们与generators的关系。我喜欢将await视为一种yield。例如,为了达到相同的行为,我们只需更改func2的主体,就是将await换成yield

function* func2() {
  console.log("Start")
  for (let i = 0; i < 10; i++) {
    if (i == 5) {
      yield new Promise(resolve => setTimeout(resolve, 0))
    }
    console.log(i);
  }
  return "done"
}

let gen = func2()
gen.next().value.then(() => console.log(gen.next().value))

console.log("main")

async / await只是使这变得更容易,对于常见用例也更加直观。