【问题标题】:Async actually not async异步实际上不是异步
【发布时间】:2020-06-24 15:07:30
【问题描述】:

以下代码:

function log() {
    console.log('ok');
}
function log2() {
    console.log('ok2');
}

async function run() {
    await log();
    await log2();
}

run();

console.log(1);

返回:

ok
1
ok2

问题是:“运行”一个异步函数不应该在所有同步调用之后执行吗? (如console.log(1))。实际上,在同步调用之后执行的是第二个await

返回值应该是:

1
ok
ok2

为什么第一个await是同步执行的?

【问题讨论】:

    标签: javascript asynchronous async-await


    【解决方案1】:

    正在“运行”一个异步函数,它不应该在所有同步调用之后执行吗?

    没有。

    使用async 关键字标记函数:

    • 让它返回一个承诺
    • 允许在其中使用 await 关键字

    它不会使同步代码异步。它不会将代码移动到另一个线程。它不会立即暂停async 函数的执行。


    所以当你调用run时,它调用log,它调用console.logok),然后返回undefinedawait 关键字导致 run 进入休眠状态,直到返回的 promise 完成。

    程序的主要部分继续运行,它记录 1

    承诺立即解决(因为它是undefined 而不是承诺),所以run 醒来并调用log2

    【讨论】:

    • 您的回答实际上让我回去阅读规范。我不清楚await 是什么实际上是有希望的。区别很微妙,但很重要,因为它意味着返回 Promise.resolve(undefined) 的普通函数与仅返回 undefined 之间的区别。你能检查我的答案并告诉我现在是否清楚吗?
    • @zero298 — 不。async 关键字使函数返回一个承诺。是 await 使函数进入睡眠状态,以便其他代码可以运行。
    【解决方案2】:

    这是我的理解。 async/await 只是 Promises 的语法糖。您的日志实际上不是异步的,它们返回 undefined

    但是,既然你说await log() 会变成Promise.resolve(log()) 并且后面的代码被放入.then()

    来自MDN

    如果 await 运算符后面的表达式的值不是 Promise,它被转换为一个已解决的 Promise。

    每当您返回 Promise 时,您都会“推迟”直到其他同步内容完成,就像 setTimeout(fn, 0) 会做的那样。因此,在同步部分完成之前,您不会看到“ok2”。

    这是另一个重要的部分。它不会运行其余的异步内容,因为它已被放入回调队列中,并且在同步内容完成之前不会被处理。请参阅 Concurrency model and the event loop 以更深入地了解如何“稍后”处理事情。

    function log() {
        console.log('ok');
    }
    function log2() {
        console.log('ok2');
    }
    
    async function run() {
    
      //await log();
      /*
       * log is called immediately and the await wraps the
       * return value in a resolved Promise, the next await
       * statement will wait for the resolved Promise which
       * pushes the callback execution to the internal runtime queue
       */
      Promise.resolve(log())
      // await log2()
      /*
       * This won't get executed until the synchronous runtime
       * runs out of stuff to do.  Once it does, this will get
       * executed
       */
        .then(() => Promise.resolve(log2()));
    }
    
    run(); // Synchronous
    
    console.log(1); // The other synchronous stuff to do

    【讨论】:

    • 清澈如水,是否有任何文件解释这种现象?
    【解决方案3】:

    异步是在幕后发生的事情。这意味着如果代码完成执行,它会输出或返回。另一方面,同步代码将照常运行。在上面的代码中,您正在控制台记录文本。这不需要太多时间来执行。所以它在完成时输出。尝试在异步代码中使用 setTimeout 可以看到同步代码先执行

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-14
      • 2017-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-16
      • 1970-01-01
      相关资源
      最近更新 更多