回 @bf 同窗 javascript
本篇文章不是筆記也不是心得,而是關於一個問題的討論,問題最初出現於https://segmentfault.com/q/1010000005630545?_ea=903562html
因爲 @bf 同窗不方便加QQ/微信,而這個問題又比較大,在問答評論裏很差描述清楚,so,趁着週末專門寫了一篇文章來回應 @bf 同窗java
@bf 同窗,提到了一個觀點:對DOM的修改永遠是異步的ajax
當時就震驚到我了(可能技術不達標,少見多怪的緣故,哈哈)編程
說實話,幹了好幾年開發,第一次明確地聽到有人這樣說,根據本身看的書及一些javascript編程經驗來講,起初我認爲是錯誤的。segmentfault
而後看了看 @bf 同窗的回覆,能自圓其說,還說的頭頭是道,因此我真的覺得對DOM的修改永遠是異步的是正確的。而後懷着震驚的心情(由於跟經驗相違背),還寫了一篇博客記錄http://www.liyanshan.com/2016/06/09/%E5%AF%B9DOM%E7%9A%84%E4%BF%AE%E6%94%B9%E6%B0%B8%E8%BF%9C%E9%83%BD%E6%98%AF%E5%BC%82%E6%AD%A5%E7%9A%84/瀏覽器
通過這麼些天的發酵和消化,以爲對這個觀點又回到了最初的認識(即這個觀點是錯的)。性能優化
還請 @bf 同窗跟我多多探討 !微信
關於javascript修改dom是異步仍是同步的問題:網絡
先來看代碼:
<ul> <li id="i0"></li> <li id="i1"></li> <li id="i2"></li> <li id="i3"></li> <li id="i4"></li> </ul> <ul id="newEle"></ul> <script> for(var i = 0;i<5;i++){ var item = document.getElementById('i'+i); item.innerHTML = i; } var newEle = document.getElementById('newEle'); for(i=0;i<5;i++){ var li = document.createElement("li"); li.innerHTML = i; newEle.appendChild(li); } </script>
上述代碼的結果徹底就是同步的表現,若是是異步的話,毫無疑問,第一個ul下的li每一個內容都應該是5,第二個也應該是5。
這是數學中的反證法。即一個命題,哪怕我找出一個特例(況且我能找出不少例子)能推翻這個命題,那麼這個命題就不成立。
@bf 同窗可能會說了,他也用反證法,好比script標籤的加載,來證實DOM修改是異步的
可是這個特例的問題在於:
把下載的異步性當成了DOM修改的異步性
script標籤加載是異步的,由於要走網絡(好比走網絡的ajax和圖片下載等都是異步的,固然ajax也能夠寫成同步的),也就是說,瀏覽器開了一個線程下載要用的script,可是立刻返回(交給HTTP請求線程就無論了,請求結束,請求線程會把結果放入事件隊列裏),接着執行或下載其餘部分。其實這個問題我在引發這個討論的問題上已經回答了(可能回答的沒有那麼清楚)。
而後又陸陸續續地看了一些書,查了一些資料,問了一些大牛,愈來愈堅信DOM修改是同步的
JavaScript異步編程第一章 - 異步的I/O函數(1.2.1)
這個也符合我最初跟 @bf 同窗的解釋:修改DOM是同步的,可是渲染是異步的。由於JavaScript引擎線程跟GUI渲染線程是互斥的,即我執行的時候,你就靠邊站,我執行完你才能執行
詳見我2014年寫的一篇關於異步的文章(當時就是記錄一下心得與筆記,也不會本身搭博客,也不會MD,因此請 @bf 同窗湊合看)http://blog.sina.com.cn/s/blog_6fd55a970102v64x.html
在羣裏提問
這個其實就至關於回答了js是同步修改的。。由於這是三個異步函數!
而 @bf 同窗在後面的回覆中,提到了一篇文章https://leozdgao.me/why-dom-slow/,額,我看了看這篇文章,發現其實我今年年初就看過了,當時貌似是用瀏覽器重排和重繪
搜索到的。。
這篇文章主要是講 重排和重繪及性能優化一類的知識。
@bf 同窗可能受到這句話的影響:
通常狀況下,瀏覽器的layout是lazy的,也就是說:在js腳本執行時,是不會去更新DOM的,任何對DOM的修改都會被暫存在一個隊列中,在當前js的執行上下文完成執行後,會根據這個隊列中的修改,進行一次layout。
這個其實說明不了修改DOM永遠是異步的,這個是JavaScript引擎實現層面上的知識,是對js修改DOM的優化,它放入的隊列其實不是事件隊列
,若是放到了事件隊列
中,纔是異步的。。C++實現一個隊列是何其簡單啊!js實現隊列更簡單!只是實現層面的東西,對程序猿都是透明的。。因此沒啥可說的。只能幫助咱們理解重排和重繪的機制,而不能得出修改DOM永遠是異步的結論。。