为什么需要事件循环
因为js是单线程 非阻塞的。
单线程:意味着,js代码执行的时候,都只有一个主线程来处理所有的任务,保证了程序执行的一致性(不会出现两个线程同时对同一个dom操作)。
非阻塞:再代码需要进行异步任务(无法立刻获取返回结果)的时候,需要挂起,在主线程空闲时根据一定的规则去指向相应的回调。js 正是通过event loop(事件循环)来实现非阻塞。
什么是事件循环
引用MDN上的说法:
事件循环用来收集事件(用户事件/其他非用户事件等)、对任务进行排队在合适的时候进行回调。 然后它执行所有处于等待中的JavaScript任务(宏任务),然后是微任务,然后开始下一次循环之前执行的一些必要渲染和绘制操作。
事件循环用来收集事件、对收集到的任务进行排队分两个队伍(宏任务、微任务),再主线程执行栈空的时候从微任务队列中取出最前面的一个事件,
在当前执行栈为空的时候,继续去微任务队列取事件直到执行空了,然后去宏任务队列中取出最前面的一个事件,把对应的回调加入当前执行栈,
在当前执行栈为空的时候,继续去微任务队列取事件直到执行空了,然后去宏任务队列中取出最前面的一个事件...如此反复,进入循环。
执行一个宏任务(先执行同步代码)-->执行所有微任务-->UI render-->执行下一个宏任务-->执行所有微任务-->UI render-->....
微任务有哪些?
promise().then(回调); async/await; MutationObserver (html5 新特性); process.nextTick;
宏任务有哪些?
js整体代码; setTimeOut, setInterval; postMessage; I/O操作; UI交互事件;
宏任务和微任务需要注意知识点
1. 宏任务、微任务的存储方式是队列(先进先出)。
2. js整体代码是宏任务,即第一次主线程执行栈空的时候 直接去执行微任务队列
3. 执行微任务队列时遇见新的微任务会放在微任务队尾本次会执行到。
4. promise().then 里面的才是微任务
new Promise(resolve => {
console.log('Promise') // 立即执行
resolve()
}).then(function() {
// 这里面的才是微任务
console.log('promise1')
})
5. await 注意:
分两种情况:
1.如果 await 后面直接跟的为一个变量,比如:await 1;这种情况的话相当于直接把await后面的代码注释成微任务如下
async function async1() {
await async2() // 立即执行
console.log('async1 end') // 直接注册成微任务
}
async function async2() {
console.log('async2 end')
return 1
}
2. 如果 await 后面的是一个异步函数的调用
微任务优先级
宏任务优先级
为什么需要有微任务队列
为了插队,如果只有一个队列,当一个promise().then(promise().then(回调2))的时候,回调2 需要排到任务队尾,如果前面的任务多,执行情况得不到保证,在宏观上看没有做到一个立即接一个地执行,而有了微任务来插队在执行上看起来像是同步。
小结练习
console.log('script start')
async function async1() {
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2 end')
return Promise.resolve().then(()=>{
console.log('async2 end1')
})
}
async1()
setTimeout(function() {
console.log('setTimeout')
}, 0)
new Promise(resolve => {
console.log('Promise')
resolve()
})
.then(function() {
console.log('promise1')
})
.then(function() {
console.log('promise2')
})
console.log('script end')
script start => async2 end => Promise => script end => async2 end1 => promise1 => promise2 => async1 end => setTimeout
node事件循环机制
参考文献
有如下三种事件循环:
- Window 事件循环
- Worker 事件循环
- Worklet 事件循环
理论部分参考:
developer.mozilla.org/en-US/docs/…
developer.mozilla.org/zh-CN/docs/…