面了一輪字節跳動,遇到一個面試題記錄一下
題目如下
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(); // 執行結果是什麼樣子的?
問題是執行以上代碼,結果是什麼樣子的?
我天真的以爲是body先變紅,兩秒後變藍色
真正的答案是:
兩秒後直接變藍!!!!
爲什麼嘞,看以下代碼執行結果就會理解其中緣由了
function demo1() {
setTimeout(()=>{
console.log('timeout 開始執行')
Promise.resolve().then(()=>{
//將dom操作移到這裏。
document.querySelector('#demo').innerHTML='red';
var now =Date.now();
while(Date.now()-now<4000){
}
console.log("微任務執行完成")
})
var now =Date.now();
while(Date.now()-now<4000){
}
console.log("宏任務執行完成")
},1000)
}
demo1();
// timeout 開始執行
// 宏任務執行完成
// 微任務執行完成
// #demo的內容顯示red
由上可知,js對dom的操作是在任務隊列裏的微任務都執行結束後才執行的。
js代碼執行由js引擎線程負責
dom樣式更改由GUI渲染線程負責
所以兩個線程互斥,造成了dom操作“異步”的效果
而且GUI渲染會進行優化,多個同一dom的操作會合並
解決辦法
- 把js線程手動滯後,通過setTimeout,js操作被放到下一個宏任務裏。
function demo () {
const now = new Date().valueOf()
// document.getElementById('demo').style.width = '200px';
document.getElementById('demo').style.backgroundColor = 'red';
setTimeout(() => {
while(new Date().valueOf() - now <= 2000) {
continue;
}
document.getElementById('demo').style.backgroundColor = 'blue';
}, 0)
}
- 可以讓GUI線程提前,通過觸發迴流的方法,讓GUI線程提前執行。