參考文章:https://segmentfault.com/a/1190000016278115
参考文章
1.任务队列与循环事件
任务队列(消息队列)可以存放要执行的任务。它符合队列“先进先出”的特点。 在任务队列中,其实还分为宏任务队列(Task Queue)和微任务队列(Microtask Queue),对应的里面存放的就是宏任务和微任务。宏任务和微任务都是异步任务。
2、事件循环系统
监听并执行消息队列中的任务
事件循环 Event Loop是一种事件执行机制。 JavaScript语言就采用这种机制,来解决单线程运行带来的一些问题
宏队列和微队列
宏队列,macrotask,也叫tasks。 一些异步任务的回调会依次进入宏队列 macro task queue,等待后续被调用,浏览器异步任务宏任务包括:比如: script(整体代码) 定时器回调、DOM 事件回调、ajax 回调
setTimeout
setInterval
UI rendering
微队列,microtask,也叫jobs。 另一些异步任务的回调会依次进入微队列 micro task queue,等待后续被调用,这些异步任务微任务包括:promise的回调、MutationObserver 的回调
Promise
Object.observe
JS 执行时会区别这 2 个队列
JS 引擎首先必须先执行所有的初始化同步任务代码
每次准备取出第一个宏任务执行前, 都要将所有的微任务一个一个取出来执行,也就是优先级比宏任务高,且与微任务所处的代码位置无关
Promise定义之后便会立即执行,其后的.then()是异步里面的微任务。
//script start
//as1 start
//as2
//prom1
//script end
//as1 end
//prom2
//setTimeOut1
//setTimeOut2
//一段代码执行时,会先执行宏任务中的同步代码:如果执行中遇到 setTimeout 之类宏任务,那么就把这个 setTimeout 推入「宏任务的队列」中,下一轮宏任务执行。
//第一个宏任务: console.log('script start')
// setTimeOut 推入「宏任务的队列」中
// 第一个微任务 as1 start
//在第一个微任务中存在await关键字,得到await右侧表达式的结果 as2 ,await会阻塞后面的代码执行,因此跳出async函数执行下一个微任务
//下一个微任务 console.log('prom1')
//碰到promise.then这个微任务会先执行本轮宏任务的同步代码 console.log('script end') 再执行微任务,先进先出 as1 end prom2
//下一轮宏任务 ,先进先出
// setTimeOut1 setTimeOut2
setTimeout(() => {
console.log('setTimeOut1')
}, 0)
async function as1(params) {
console.log('as1 start')
await as2()
console.log('as1 end')
}
async function as2(params) {
console.log('as2')
}
console.log('script start')
setTimeout(() => {
console.log('setTimeOut2')
}, 0)
as1()
new Promise((resolve, reject) => {
console.log('prom1')
resolve()
}).then(() => {
console.log('prom2')
})
console.log('script end')
//3 7 4 1 2 5
//宏 5
//微 3 7 4 1 2
const first = () => (new Promise((resolve, reject) => {
console.log(3)
let p = new Promise((resolve, reject) => {
console.log(7)
setTimeout(() => {
console.log(5)
resolve(6) //会被忽略,因为会先执行微队列里的resolve(1),此时状态已经改变过了,且状态只能改变一次
}, 0)
resolve(1)
})
resolve(2)
p.then((arg) => {
console.log(arg + '1---')
})
}))
first().then((arg) => {
console.log(arg + '2xxx')
})
console.log(4)
//宏任务 0
//微任务 1 7 2 3 8 4 6 5
//1 7 2 3 8 4 6 5 0
setTimeout(() => {
console.log("0")
}, 0)
new Promise((resolve, reject) => {
console.log("1")
resolve()
}).then(() => {
console.log("2")
new Promise((resolve, reject) => {
console.log("3")
resolve()
}).then(() => {
console.log("4")
}).then(() => {
console.log("5")
})
}).then(() => {
console.log("6")
})
new Promise((resolve, reject) => {
console.log("7")
resolve()
}).then(() => {
console.log("8")
})