事件轮询与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.背景颜色变为绿色})})
所以弹窗时背景颜色为粉色,点击后变为绿色