代码
function demo(){
const now = new Date().valueOf()
document.body.style.backgroundColor = 'red';
while ((new Date()).valueOf() - now <= 2000) {
continue;
}
document.body.style.backgroundColor = 'blue';
}
demo(); //执行结果是什么样子的?
真正的答案是没有变红,直接两秒后变蓝
究其原因,看下以下代码就知道哦
function demo1(){
setTimeout(function () {
Promise.resolve().then(function () {
const now = new Date().valueOf()
document.body.style.backgroundColor = 'red';
while ((new Date()).valueOf() - now <= 2000) {
continue;
}
console.log('微任务完成')
})
const now = new Date().valueOf()
while ((new Date()).valueOf() - now <= 2000) {
}
console.log('宏任务完成')
}, 1000)
}
demo1(); //执行结果是什么样子的?
由上可知,js对dom的操作是在任务队列里的微任务都执行结束后才执行的。
js代码执行由js引擎线程负责
dom样式更改由GUI渲染线程负责
所以两个线程互斥,造成了dom操作“异步”的效果
而且GUl渲染会进行优化,多个同-dom的操作会合并
执行一个宏任务(栈中没有就从事件队列中获取)
执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染>
渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)
解决办法
- 将js线程手动滞后,通过setTimeout,js操作被放到下一个宏任务里。
function demo(){
const now = new Date().valueOf()
document.body.style.backgroundColor = 'red';
setTimeout(()=> {
while ((new Date()).valueOf() - now <= 2000) {
continue;
}
document.body.style.backgroundColor = 'blue';
})
}
demo(); //执行结果是什么样子的?
- 可以让GUI线程提前,通过触发回流的方法,让GUI线程提前执行。