浏览器事件循环
js在浏览器有事件循环机制的原因
-
js是单线程
-
通过 event loop 实现异步、非阻塞事件
事件循环的任务
-
宏任务
-
将任务排到下一个事件循环
- 代码块、setTimeout、setInterval、setImmediate(Node)、requestAnimationFrame(浏览器)、IO操作、网络请求
-
-
微任务
-
将任务排到当前事件循环的队尾
-
new Promise().then、Object.observe、MutationObserver(mutation 突变,前端的回溯)、process.nextTick(Node)
-
MutaionObserverlet observer = new MutationObserver(()=>{ console.log(1); }) let node = document.createElement('div') observer.observe(node, { // 监听节点 childList: true // 一旦改变则触发回调函数 nextTickHandler }) node.innerHTML = 1 -
用
MutaionObserver封装一个微任务执行函数let nextTick = (function () { let callbacks = [] function nextTickHandler() { let copies = callbacks.slice(0) callbacks = [] for (let i = 0; i < copies.length; i++) { copies[i]() } } let counter = 1 let observer = new MutationObserver(nextTickHandler) // 声明 MO 和回调函数 let node = document.createElement('div') observer.observe(node, { // 监听节点 childList: true // 一旦改变则触发回调函数 nextTickHandler }) return function (cb) { callbacks.push(cb) counter = (counter + 1) % 2 //让节点内容文本在 1 和 0 间切换 node.innerHTML = counter } })()
-
-
-
完成宏任务后去清空微任务队列
-
微任务存在的原因
-
宏任务:先进先出
-
执行宏任务(页面变化)时,用来检测判断对象发生变化的
-
宏任务&微任务-事件循环
-
Event Loop(事件循环)
-
同步的进入主线程,异步的进入 Event Table 并注册函数
-
完成指定的事情后,Event Table 会将这个函数移入 Event Queue
-
主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行
-
上述过程会不断重复
-
-
执行
-
先放入:宏任务一个eventqueue,再微任务另一个eventqueue
-
外拿时:先从微任务里拿回掉函数,再从宏任务的queue上拿宏任务的回掉函数
-
Node中的事件循环和浏览器中事件循环的区别
-
宏任务执行顺序
-
timers 定时器
- 执行已经安排的setTimeout和setInterval的回调函数
-
pending callback 待定回调
- 执行延迟到下一个循环迭代的I/O回调
-
idle,prepare
- 仅系统内部使用
-
poll 轮询
- 检索新的I/O事件,执行相关的回调
-
check
- 执行 setImmediate() 回调函数
-
close callback
- socket.on('close',() => {})
-
-
微任务和宏任务在node的执行顺序
-
Node v10 之前
-
执行完一个阶段的所有任务
-
执行 nextTick 队列里的内容
-
执行 微任务队列 的内容
-
-
Node v10 之后
- 和浏览器行为统一
-
-
代码
-
await 描述的函数相当于放进 new Promise 里面,后面的语句放入 .then 里面
-
async 的函数要被调用才会触发
async function async1() { console.log('async1 start') await async2() console.log('async1 end') } async function async2() { console.log('async2') } console.log('script start') setTimeout(function () { console.log('setTimeout') }, 0) async1() new Promise(function (resolve) { console.log('promise1') resolve() }).then(function () { console.log('promise2') }) console.log('script end') // script start // async1 start // async2 // promise1 // script end // async1 end // promise2 // setTimeout-
promise 没有 resolve 的时候,它的 .then 不会被添加到微任务队列中,还在宏任务
-
children6 放到了 .then 的 res 里面,被 resolve 延迟执行
-