事件轮询与DOM渲染
总结
JS代码执行顺序为:
宏任务(script代码) => 微任务 => DOM渲染 => 异步宏任务
首先看下列代码:
// 为document对象绑定点击事件
document.documentElement.addEventListener(`click`,()=>{
// 先将文档背景颜色改为粉色
document.documentElement.style.backgroundColor="pink"
// 设置定时器
setTimeout(()=>{
// alert弹窗阻塞线程 便于观察当前页面背景颜色
alert(``)
// 背景颜色改为绿色
document.documentElement.style.backgroundColor="green"
})
})
代码的执行结果为背景颜色变为粉色,弹出弹窗,点击背景颜色变为绿色
跟我们预期的结果一样
而同样是异步代码,将setTimeout换为Promise后
document.documentElement.addEventListener(`click`,()=>{
document.documentElement.style.backgroundColor="pink"
Promise.resolve().then(()=>{
alert(``)
document.documentElement.style.backgroundColor="green"
})
})
代码的执行结果为弹窗(背景颜色是白色),点击背景颜色变为绿色
document.documentElement.style.backgroundColor="pink" // <----这行代码不生效了???
同样都是先同步后异步为什么会有这种区别呢
原因就是DOM渲染顺序的问题。
click是异步宏任务,点击之后click函数代码事件循环进入执行栈,此时执行click里的宏任务,
DOM渲染的代码虽然是宏任务,但执行后不会马上渲染到页面,它的优先级在微任务之后
然后执行到Promise,把then后的代码添加到微任务队列,
此时微任务队列的优先级高于DOM渲染,所以先执行微任务,
宏任务里的背景颜色(粉色)还没渲染,就被then里面的微任务代码(绿色)覆盖了
实际的执行顺序为
document.documentElement.addEventListener(`click`,()=>{
document.documentElement.style.backgroundColor="pink"
//1.背景颜色粉色(未渲染)
Promise.resolve().then(()=>{
alert(``) //2.弹窗
document.documentElement.style.backgroundColor="green"
//3.背景颜色绿色(未渲染,将粉色覆盖)
})
//4.DOM 渲染 背景颜色
})
由上到下执行,所以alert时背景颜色没变,点击确认后,背景绿色,DOM渲染,页面就为绿色
而setTimeout是异步宏任务,是在宏任务,微任务和DOM渲染执行完后才执行
这里因为没有微任务,所以执行顺序就为宏任务 DOM渲染 异步宏任务(定时器)
document.documentElement.addEventListener(`click`,()=>{
document.documentElement.style.backgroundColor="pink"
//1.同步代码 执行完后 马上DOM渲染 背景颜色变为粉色
setTimeout(()=>{
alert(``) //2.弹窗
document.documentElement.style.backgroundColor="green"
//3.背景颜色变为绿色
})
})
所以弹窗时背景颜色为粉色,点击后变为绿色