- 任务分为同步任务和异步任务,一个任务通常由多个桢组成
- 同步任务是放在运行栈中的,而异步任务会被浏览器的timer模块拿走,不会放在运行栈中
- 任务进入执行栈,同步任务就直接执行,异步任务放到异步队列中
- 异步任务分为宏任务和微任务,常见宏任务:I/O 、setTimeout、setInterval;微任务:Promise.then catch finally、process.nextTick
- 执行完所有的微任务就执行下一个宏任务,如此往复(同一次事件循环中,微任务总是在宏任务之前执行)
- async函数表示函数里面可能会有异步方法,await后面跟一个表达式,async方法执行时,遇到await会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行。
- 不管同步任务、微任务还是宏任务都是在主线程执行的,所以内部的代码的执行顺序和整个流程一个(类似于递归)
解释一下,同步任务拿到都是直接执行的,所以都是在任务队列的最前面,而异步任务在执行到的时候才会被push进任务队列,比如setTimeout的延时,而异步任务又分为宏任务和微任务,所以我把任务队列看成三部分,同步队列、宏任务队列和微任务队列,不管是宏任务还是微任务都是回到主线程执行的(因为JavaScript是单线程的),所以它们内部的代码也遵守这个规则,拿段代码来具体解释一下
console.log(0)
setTimeout(function(){
console.log('set1')
new Promise(function(resolve,reject){
console.log(1)
resolve()
}).then(function(){
console.log('then3')
})
},1000)
var p = new Promise(function(resolve,reject){
console.log('promise1')
setTimeout(function(){
console.log('set2')
})
resolve()
})
p.then(function(){
console.log('then1')
})
setTimeout(function(){
console.log('set3')
})
var p2 = new Promise(function(resolve,reject){
console.log('promise2')
resolve()
})
p2.then(function(){
console.log('then2')
})
console.log(123)
1.console.log(0)是同步任务,直接输出0
2.setTimeout是宏任务,在1s之后执行时push进任务队列
3.promise内部是同步任务,只有.then是异步任务,所以输出promise1,并将set2放进宏任务队列,此时宏任务 = [set2]
4.promise.then是微任务,将then1放入微任务队列 ,微任务 = [then1]
5.将set3放进宏任务队列,此时宏任务 = [set2,set3]
6.输出promise2
7.将then2放入微任务队列,此时微任务 = [then1,then2]
8.输出123
9.同步任务执行完毕,询问微任务队列,执行所有的微任务,即执行then1,then2,输出then1,then2,微任务 = [ ]
10.执行下一个宏任务set2,输出set2,没有微任务,则执行下一个宏任务,此时宏任务 = [set3]
11.执行set3,输出set3,宏任务 = [ ]
10.1s后set1被push进任务队列,执行宏任务set1,输出set1,1,将then3添加进微任务队列,微任务 = [then3]
10.执行完一个宏任务,再询问微任务,执行then3,输出then3
最终输出顺序为0,promise1,promise2,123,then1,then2,set2,set3,set1,1,then3