【问题标题】:What the execution order of asynchronous functions if there are multiple in one thread?如果一个线程中有多个异步函数的执行顺序是什么?
【发布时间】:2019-01-17 22:39:47
【问题描述】:

我正在学习 JavaScript 中异步函数的概念。我知道 JavaScript 是单线程的,回调函数放在线程中的同步可执行代码后面。这篇文章解释得很好。 https://www.sohamkamani.com/blog/2016/03/14/wrapping-your-head-around-async-programming/

但是文章没有解释我的一个问题,如果代码中有多个回调函数怎么办?比如下面的代码,执行顺序是什么?是先执行异步函数1还是异步函数2?

var request = require('request');

// async function 1: take 200ms
request('http://sohamkamani.com', function (error, response, body) {
  console.log(body);
})

// async function 2: take 100ms
request('http://facebook.com', function (error, response, body) {
  console.log(body);
})

console.log('I come after the request');

【问题讨论】:

标签: javascript asynchronous single-threaded


【解决方案1】:

根据您对事件的描述,以下是大致的情况。这里的重要概念涉及异步处理、调用堆栈和事件队列。

  1. 您的脚本,我们称之为main.js,将被添加到调用堆栈。您的调用堆栈现在如下所示:

    • main.js
  2. main.js 开始执行。第一行被添加到调用堆栈。您的调用堆栈现在如下所示:

  3. 请求被执行,并且只要回调被解决,就会被跟踪。由于这里没有其他事情可做,因此它已从调用堆栈中删除。所以你的调用栈现在看起来像这样:

    • main.js
  4. main.js 中的下一行被添加到调用堆栈中。

  5. 同样,请求被执行,并且每当回调被解决时都会被跟踪。它从调用堆栈中移除。

    • main.js
  6. 下一行被添加到调用栈

    • console.log('I come after the request');
    • main.js
  7. 这可以立即执行并将请求发送到您的控制台以记录这句话。您的调用堆栈现在如下所示:

    • main.js
  8. main.js 完成后,可以将其从调用堆栈中移除。您的调用堆栈现在是空的。

  9. facebook 请求在 100 毫秒后解决。回调函数function (error, response, body) { ... } 被添加到事件队列。事件队列中的东西只有在调用栈清空后才能执行。

  10. 您的调用堆栈已清除! facebook 回调函数被添加到调用堆栈并被执行。发送控制台日志。回调函数从调用堆栈中移除。

  11. 200 毫秒后,sohamkamani.com 解析并将其回调函数发送到事件队列。您的调用堆栈很清晰!回调函数被添加到调用堆栈,执行,并从调用堆栈中删除。

【讨论】:

    【解决方案2】:

    请求将按照您对其进行编码的顺序开始。将发送到http://sohamkamani.com 的请求,然后发送到http://facebook.com 的请求。但是你无法知道回调的顺序,因为它们只会在服务器响应时执行,而你不知道那是什么时候。

    关于代码输出,您唯一确定的是I come after the request 将是首先写入控制台的内容,这将在两个请求都发送之后但在它们的回调执行之前发生。

    【讨论】:

    • 我认为这几乎是对的,但真正的细节是回调函数将被添加到事件队列中,以便在调用堆栈被清除后按顺序执行。
    • 是的,如果两个请求同时返回@Nick,我想这是边缘情况,但更大的一点是,我们不知道是否会出现这种情况,所以我们不知道回调将触发的顺序。
    • 这是很好的解释。谢谢@Nick 和@Mark!
    • 重要的是要注意回调函数进入事件队列只有在调用堆栈被清除后才会执行。换句话说,无论这些请求解决的速度有多快(即使是瞬间解决),console.log(body) 都不可能在console.log('I come after the request'); 之前发生
    • 另一个小细节是,这些回调只有在响应进入后才会被推送到队列中。这意味着可能会有更多——甚至是异步的——要填充的代码排队并提前运行。
    猜你喜欢
    • 1970-01-01
    • 2021-08-15
    • 2019-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多