JS中的事件分为两种,一种是同步,一种是异步。首先执行同步事间,然后执行异步事件。在异步事件的任务队列中,又分为宏任务和微任务,先执行微任务再执行宏任务。宏任务主要包括script( 整体代码)、setTimeout、setInterval、I/O、UI 交互事件、setImmediate(Node.js 环境);微任务主要包括Promise、MutaionObserver、process.nextTick(Node.js 环境)。下面看一段代码。
window.onload = function () {
console.log("script start")
async function async1() {
await async2()
console.log("async1 end");
}
async function async2() {
console.log("async2 end");
}
async1()
setTimeout(function () {
console.log("setTimeout");
})
new Promise(function (resolve) {
console.log("Promise");
resolve();
}).then(function () {
console.log("promise1")
}).then(function () {
console.log("promise2")
})
console.log("script end")
}
打印结果为:
代码解释:首先我们将这个async1函数给转为promise(async/await本身就是promise的语法糖,可以相互转换),结果为
window.onload = function () {
console.log("script start")
function async1() {
new Promise(function (resolve) {
console.log("async2 end");
resolve();
}).then(function () {
console.log("async1 end");
})
}
async1()
setTimeout(function () {
console.log("setTimeout");
})
new Promise(function (resolve) {
console.log("promise");
resolve();
}).then(function () {
console.log("promise1")
}).then(function () {
console.log("promise2")
})
console.log("script end")
}
执行顺序为:打印script start,async2 end,遇见promise.then放入微任务队列,遇见setTimeout放入宏任务队列,打印promise,遇见promise.then放入微任务队列,打印script end。也就是说首先打印script start、async2 end、promise、script end,然后执行微任务队列的,async1 end、promise1、promise2,最后打印宏任务setTimeout。
那么我把代码修改一下被?如下所示,又会打印什么?
window.onload = function () {
console.log("script start")
function async1() {
new Promise(function (resolve) {
setTimeout(function(){
console.log("async2 end")
},0)
resolve();
}).then(function () {
setTimeout(function(){
console.log("async1 end")
},0)
})
}
async1()
setTimeout(function () {
console.log("setTimeout");
},0)
new Promise(function (resolve) {
console.log("Promise");
resolve();
}).then(function () {
console.log("promise1")
}).then(function () {
console.log("promise2")
})
console.log("script end")
}
首先打印同步事件,script strat、promise、script end,再打印微任务队列中的事件,peomise1、promise2,最后打印宏任务队列的事件,async2 end、setTimeout、async1 end。那么为什么setTimeout不是最后呢?因为 console.log("async2 end")这行代码在微任务队列中的宏任务队列,所以最后执行,倘若是打印setTimeout的时候给的给的时间大于0,那么setTimeout就还是在最后了。