setTimeout、Promise、Async/Await 的执行顺序
程序员文章站
2022-03-20 16:48:51
Javascript 有一个 main thread 主线程和 call-stack 调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。 JS调用栈采用的是后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。 Javascript单线程 ......
问题描述:以下这段代码的执行结果
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
单线程任务被分为同步任务和异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。
在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版本)
(73及以上版本执行结果为)
script start async1 start async2 promise1 script end async1 end promise2 settimeout
上一篇: Go-常见的面试题(一)
下一篇: 关于使用宏将csv批量转换成xls的分享
推荐阅读
-
async/await与promise(nodejs中的异步操作问题)
-
详解koa2学习中使用 async 、await、promise解决异步的问题
-
实例详解JavaScript中setTimeout函数的执行顺序
-
详解promise.then,process.nextTick, setTimeout 以及 setImmediate的执行顺序
-
解决循环中setTimeout执行顺序的问题
-
宏任务和微任务:setTimeout和Promise执行顺序
-
Promise, Generator, async/await的渐进理解
-
vue 同步 $nextTick setTimeout 执行的顺序
-
Js中async/await的执行顺序详解
-
JS中的async/await的执行顺序详解