記一道字節跳動的面試題 js操作dom的執行順序

面了一輪字節跳動,遇到一個面試題記錄一下

題目如下

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的操作會合並

解決辦法

  1. 把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)
}
  1. 可以讓GUI線程提前,通過觸發迴流的方法,讓GUI線程提前執行。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章