天天看点

setTimeout、Promise、Async/Await 的执行顺序

问题描述:以下这段代码的执行结果      
async function async1() {
        console.log('async1 start');
        await async2();
        console.log('asnyc1 end');
    }
    async function async2() {
        console.log('async2');
    }
    console.log('script start');
    setTimeout(() => {
        console.log('setTimeOut');
    }, 0);
    async1();
    new Promise(function (reslove) {
        console.log('promise1');
        reslove();
    }).then(function () {
        console.log('promise2');
    })
    console.log('script end');      
解决问题:
      
要了解代码的执行顺序 必须先了解 JS的运行机制      
  •  Javascript

    有一个

    main thread

    主线程和

    call-stack

    调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。
  • JS调用栈采用的是后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。
  •  Javascript

    单线程任务被分为同步任务和异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。
setTimeout、Promise、Async/Await 的执行顺序
setTimeout、Promise、Async/Await 的执行顺序

JavaScript

中,任务被分为两种,一种宏任务(

MacroTask

),一种叫微任务(

MicroTask

)。

MacroTask(宏任务)

  • script

    全部代码、

    setTimeout

    setInterval

MicroTask(微任务)

  • Promise、await

执行栈在执行完 同步任务后,查看 执行栈是否为空,如果执行栈为空,就会去检查 微任务队列是否为空,如果为空的话,就执行宏任务,否则就一次性执行完所有微任务。

每次单个 宏任务执行完毕后,检查 微任务队列是否为空,如果不为空的话,会按照 先入先出的规则全部执行完 微任务后,设置 微任务队列为

null

,然后再执行 宏任务,如此循环。     运行之前我们需要知道以下几点

  • setTimeout属于宏任务
  • Promise本身是同步的立即执行函数,Promise.then属于微任务
  • async方法执行时,遇到await会立即执行表达式,表达式之后的代码放到微任务执行

下面我们就来运行代码

第一次执行:执行同步代码

Tasks(宏任务):run script、 setTimeout callback

Microtasks(微任务):await、Promise then

      
JS stack(执行栈): script

      
Log: script start、async1 start、async2、promise1、script end      

第二次执行:执行宏任务后,检测到微任务队列中不为空、一次性执行完所有微任务

Tasks(宏任务):run script、 setTimeout callback

Microtasks(微任务):null

JS stack(执行栈): await、Promise then

      
Log: script start、async1 start、async2、promise1、script end、promise2、async1 end      

第三次执行:当微任务队列中为空时,执行宏任务,执行

setTimeout callback

,打印日志。

Tasks(宏任务):null

Microtasks(微任务):null

JS stack(执行栈):setTimeout callback

      
Log: script start、async1 start、async2、promise1、script end、promise2、async1 end、setTimeout
      

关于73以下版本和73版本的区别

  • 在老版本版本以下,先执行

    promise2

    ,再执行

    async1 end

  • 在73及以上版本,先执行

    async1 end

    再执行

    promise2

  • 具体资料可以查询  https://v8.js.cn/blog/fast-async/

 于是我们就得到了这段代码的执行结果(70版本)

setTimeout、Promise、Async/Await 的执行顺序

(73及以上版本执行结果为)

script start
async1 start
async2
promise1
script end
async1 end promise2 setTimeout      

转载于:https://www.cnblogs.com/dajuyiding/p/11355677.html

继续阅读