亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

title: JS中操作DOM是"同步"還是"異步"? date: 2019-08-08 17:55:00 tags:

  • JAVAScript categories: JavaScript

很多時(shí)候"不得已"使用js操作DOM,這個(gè)操作過(guò)程到底是"同步"的還是"異步"呢?

很多時(shí)候"不得已"使用js操作DOM,這個(gè)操作過(guò)程到底是"同步"的還是"異步"呢?

一、操作DOM的栗子

按理說(shuō),在js的執(zhí)行中,對(duì)于DOM的操作都是同步執(zhí)行的,

<body></body>
<script>
 var body = document.querySelector('body');
 console.log(`1`);
 var cDiv = document.createElement('div');
 console.log(cDiv)
 console.log(`2`);
 body.AppendChild(cDiv)
 console.log(body);
</script>

以上結(jié)果目前和我們預(yù)想的結(jié)果是一致的,自上而下依次同步執(zhí)行,這里劃重點(diǎn),js引擎線程。

接下來(lái)做一點(diǎn)修改

<style>

.easy {

width: 200px;

height: 200px;

background: lightgoldenrodyellow;

}

.hard {

background: lightsalmon;

transition: 2s all;

}

</style>

<body></body>

<script>

var body = document.querySelector('body');

console.log(`1`);

var cDiv = document.createElement('div');

console.log(cDiv);

console.log(`2`);

body.appendChild(cDiv)

console.log(body);

cDiv.classList.add('easy')

console.log(`3`);

// ======================

for(var i = 0;i<3000000000;i++);

cDiv.classList.add('hard')

console.log(cDiv)

// ======================

</script>

既然是同步執(zhí)行,那我在添加第二個(gè)樣式hard之前阻塞一下,理論上在阻塞的情況下<div>應(yīng)該的背景色是淡黃色吧?不過(guò)跑一下完全不對(duì)勁啊,出來(lái)的很慢不說(shuō),竟然直接就橘色了。這里劃重點(diǎn),GUI渲染線程

二、捋一捋問(wèn)題

  1. 有阻塞,在阻塞時(shí)沒(méi)有顯示已有樣式,究竟是不是同步執(zhí)行的?
  2. console.log()的內(nèi)容并不是空,只是返回的很慢,看著像異步執(zhí)行?
  3. 過(guò)度樣式被忽略了,但背景色覆蓋執(zhí)行了,是什么原因?

三、依次解題

  1. js執(zhí)行順序不在這里細(xì)說(shuō),常見(jiàn)能夠改變執(zhí)行隊(duì)列的Promise、setTimeout、<script>標(biāo)簽等等都沒(méi)有在這里出現(xiàn),所以確認(rèn)是同步執(zhí)行無(wú)疑。
  2. 既然同步執(zhí)行為什么會(huì)有"異步"的效果,這里要說(shuō)到上文劃重點(diǎn)內(nèi)容: js引擎線程與GUI渲染線程。也就是說(shuō),js引擎線程與GUI渲染線程互斥,這是線程之間的"同步"造成的操作DOM時(shí)的"異步"效果。
  3. <div>的樣式為什么沒(méi)有生效呢?明明有一個(gè)過(guò)渡效果。原因是:瀏覽器的渲染時(shí)會(huì)執(zhí)行優(yōu)化策略,即將多個(gè)同一DOM下的樣式合并后渲染。

四、 總結(jié)

  1. js引擎線程與GUI渲染線程線程間的互斥,引起了對(duì)js操作DOM的"異步"問(wèn)題。
  2. GUI渲染線程在能夠執(zhí)行的情況下的優(yōu)化策略,渲染出的是最終得到的樣式結(jié)果。

具體的渲染線程的內(nèi)容,不在這次討論范圍之內(nèi)嘛。

雖然原因找到了,不過(guò)問(wèn)題好像還在。

五、 解決問(wèn)題

如果產(chǎn)品一定要從js創(chuàng)建出來(lái)的div擁有炫酷的特效(比如上面的過(guò)度樣式)。 呵呵呵呵

直接整理一下來(lái)自知乎各方大佬的解題思路, 這里不僅僅是過(guò)度樣式,類似問(wèn)題依然有效。

分析問(wèn)題:

  1. 過(guò)度效果是至少由A變B,也就是至少存有兩個(gè)不同狀態(tài);
  2. 由于上文所講的GUI渲染線程與js引擎的互斥會(huì)造成一種"同步"執(zhí)行的效果,所以創(chuàng)建<div>本身已經(jīng)被滯后了,缺少A。
  3. 又由于GUI渲染線程優(yōu)化策略,最后結(jié)果B將覆蓋可以覆蓋的所有。缺少了A(被覆蓋),之后被渲染出現(xiàn)在document內(nèi)。
  4. 本身已經(jīng)是B,且沒(méi)有A狀態(tài),過(guò)度效果無(wú)效。

解決方向就是使<div>擁有一個(gè)初始狀態(tài)A就搞定了。(提前將生成的DOM渲染到document上)


解決方法一:

	cDiv.classList.add('easy')
	// for(var i = 0;i<3000000000;i++);
	setTimeout(() => {
		cDiv.classList.add('hard')
	}, 0)

思路: 利用setTimeout方法,改變執(zhí)行隊(duì)列。也就是手動(dòng)將js引擎滯后,使js引擎結(jié)束,被掛起的GUI渲染線程執(zhí)行,擁有了初始狀態(tài)A后,在執(zhí)行過(guò)度效果就OK了。

解決方法二(推薦):

	cDiv.classList.add('easy')
	cDiv.clientLeft; // 任一觸發(fā)頁(yè)面回流的方法皆可
	cDiv.classList.add('hard')

思路:既然可以讓js引擎滯后,那也可以讓GUI渲染線程提前,用立即觸發(fā)回流的任意方法,使之前在渲染隊(duì)列中的狀態(tài)A生效。 相對(duì)優(yōu)點(diǎn)在于,同樣是觸發(fā)回流,方法二從代碼可讀性或操作性上都略勝一籌,優(yōu)秀團(tuán)隊(duì)有這種追求也是自然而然的。

分享到:
標(biāo)簽:DOM
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定