代码之家  ›  专栏  ›  技术社区  ›  zhangjinzhou

async是否使它内部的所有内容都是异步的?

  •  2
  • zhangjinzhou  · 技术社区  · 6 年前

    根据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 回复  |  直到 6 年前
        1
  •  6
  •   jfriend00    6 年前

    async是否使它内部的所有内容都是异步的?

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

    如果同步代码仍然是同步的,那么异步的目的是什么?只允许在里面等待并提供某种奇特的方式来回报承诺?

    是的,主要是为了 await 是的。

    但是,有时它会自动用承诺包装您的代码这一事实很有用。例如,它会自动捕获任何抛出的异常,并将它们转换为被拒绝的承诺。有时候这很有用。有关此其他用途的示例,请参阅本文的“错误处理”部分: 6 Reasons Why JavaScript’s Async/Await Blows Promises Away 是的。

    但是, async 关键字是定义一个函数,您可以在其中使用 等待 是的。这就是ES7的设计者决定 等待 工作。

    仅供参考,如果有 等待 在等待承诺的函数中,则会导致函数在 等待 是的。它将在那一点上返回并返回一个承诺。您正在等待的操作将启动,在等待的承诺得到解决之前,函数的其余部分将不会执行。所以,使用 等待 使一些代码稍后执行。但是,和之前的代码一样 等待 ,即使函数在 等待 已经解决了,该函数中的javascript仍然是同步的和阻塞的(直到另一个 等待 或者直到 return )中。

    把它包装成一个承诺并检测它什么时候结束 .then() 会推迟到 .然后() 在事件循环的下一个滴答声之前调用处理程序。那么,那么 .然后() 会稍微延迟,因为你把它包在一个承诺里,然后用 .然后() ,但代码运行的时间不会更改。它仍然是同步的和阻塞的。

    在javascript中,获得同步代码并使其异步的唯一方法是:

    1. 在另一个进程中运行它 并使用进程间通信来反馈结果。

    2. 在本机代码外接程序中重写代码 它使用本机线程或其他一些操作系统异步接口来完成实际工作,然后从您的插件向javascript提供异步接口(通常是通过回调返回承诺或通知完成的接口)。现在这是node.js异步函数,例如 fs.readFile() 工作。它们有一个立即返回的本机代码实现,然后在实现中使用本机线程并通过回调通知完成。

    3. 使用一些node.js附加组件来完成这些任务。 有些插件声称提供线程。

    4. 在节点版本10.5中使用node.js线程+ 以及他们所要求的限制。以下是一篇关于这个主题的文章: Threads in Node 10.5.0: a practical intro

        2
  •  4
  •   Mark    6 年前

    不,异步函数中的主体在调用时运行,但在 await 表达。如果没有什么 等待 ,该函数将像普通函数一样运行,但它返回一个promise。

    但是如果 等待 ,执行暂停,事件循环继续。当等待的承诺在当前事件循环完成后的某个时间解决时,它将从停止的地方开始。例如,比较“main”在这里记录的时间与您的示例。

    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 是的。我喜欢想 等待 作为一种 yield 是的。例如我们唯一需要改变的就是 func2 得到同样的行为就是交换 等待 对于 产量 以下内容:

    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")

    异步 / 等待 只是让这更容易,对于常见的用例来说更直观一些。