摘要:也就是說是亂序的,而是順序執行,這也就決定了比較適用于百度分析或者谷歌分析這類不依賴其他腳本的庫。然而,這張圖幾乎是百度搜到的唯一答案是不嚴謹的,這只是規范的情況,大多數瀏覽器在實現的時候會作出優化。
1. 什么鬼
今天在做一個小需的時候,忽然看到前輩一句吊炸天的代碼
臥槽,竟然同時有async和defer屬性,心想著肯定是前輩老司機的什么黑科技,兩個一塊兒肯定會發生什么神奇化學反應,于是趕緊懷著一顆崇敬的心去翻書翻文檔,先復習一下各自的定義。
2. 調查一番先看看async和defer各自的定義吧,翻開紅寶書望遠鏡,是這么介紹的
2.1 defer2.2 async這個屬性的用途是表明腳本在執行時不會影響頁面的構造。也就是說,腳本會被延遲到整個頁面都解析完畢后再運行。因此,在元素中設置defer屬性,相當于告訴瀏覽器立即下載,但延遲執行。
HTML5規范要求腳本按照它們出現的先后順序執行,因此第一個延遲腳本會先于第二個延遲腳本執行,而這兩個腳本會先于DOMContentLoaded事件執行。在現實當中,延遲腳本并不一定會按照順序執行,也不一定會在DOMContentLoad時間觸發前執行,因此最好只包含一個延遲腳本。
這個屬性與defer類似,都用于改變處理腳本的行為。同樣與defer類似,async只適用于外部腳本文件,并告訴瀏覽器立即下載文件。但與defer不同的是,標記為async的腳本并不保證按照它們的先后順序執行。
第二個腳本文件可能會在第一個腳本文件之前執行。因此確保兩者之間互不依賴非常重要。指定async屬性的目的是不讓頁面等待兩個腳本下載和執行,從而異步加載頁面其他內容。
概括來講,就是這兩個屬性都會使script標簽異步加載,然而執行的時機是不一樣的。引用segmentfault上的一個回答中的一張圖藍色線代表網絡讀取,紅色線代表執行時間,這倆都是針對腳本的;綠色線代表 HTML 解析。
也就是說async是亂序的,而defer是順序執行,這也就決定了async比較適用于百度分析或者谷歌分析這類不依賴其他腳本的庫。從圖中可以看到一個普通的標簽的加載和解析都是同步的,會阻塞DOM的渲染,這也就是我們經常會把寫在底部的原因之一,為了防止加載資源而導致的長時間的白屏,另一個原因是js可能會進行DOM操作,所以要在DOM全部渲染完后再執行。
2.3 really?然而,這張圖(幾乎是百度搜到的唯一答案)是不嚴謹的,這只是規范的情況,大多數瀏覽器在實現的時候會作出優化。
來看看chrome是怎么做的
《WebKit技術內幕》:
當用戶輸入網頁URL的時候,WebKit調用其資源加載器加載該URL對應的網頁。
加載器依賴網絡模塊建立連接,發送請求并接受答復。
WebKit接收到各種網頁或者資源的數據,其中某些資源可能是同步或異步獲取的。
網頁被交給HTML解釋器轉變成一系列的詞語(Token)。
解釋器根據詞語構建節點(Node),形成DOM樹。
如果節點是JavaScript代碼的話,調用JavaScript引擎解釋并執行。
JavaScript代碼可能會修改DOM樹的結構。
如果節點需要依賴其他資源,例如圖片、CSS、視頻等,調用資源加載器來加載他們,但是他們是異步的,不會阻礙當前DOM樹的繼續創建;如果是JavaScript資源URL(沒有標記異步方式),則需要停止當前DOM樹的創建,直到JavaScript的資源加載并被JavaScript引擎執行后才繼續DOM樹的創建。
所以,通俗來講,chrome瀏覽器首先會請求HTML文檔,然后對其中的各種資源調用相應的資源加載器進行異步網絡請求,同時進行DOM渲染,直到遇到標簽的時候,主進程才會停止渲染等待此資源加載完畢然后調用V8引擎對js解析,繼而繼續進行DOM解析。我的理解如果加了async屬性就相當于多帶帶開了一個進程去獨立加載和執行,而defer是和將放到底部一樣的效果。
3. 實驗一發 3.1 demo為了驗證上面的結論我們來測試一下
Document ul>li{這是第$個節點}*1000
一個簡單的demo,從各個CDN上引用了2個CSS3個JS,在body里面創建了1000個li。通過調整外部引用資源的位置和加入相關的屬性利用chrome的Timeline進行驗證。
3.2 放置在內
異步加載資源,但會阻塞的渲染會出現白屏,按照順序立即執行腳本
異步加載資源,等中的內容渲染完畢后且加載完按順序執行JS
異步加載資源,且加載完JS資源立即執行,并不會按順序,誰快誰先上
異步加載資源,在DOM渲染后之后再按順序執行JS
表現和async一致,開了個腦洞,把這兩個屬性交換一下位置,看會不會有覆蓋效果,結果發現是一致的 = =、
綜上,在webkit引擎下,建議的方式仍然是把寫在底部,如果需要使用百度谷歌分析或者不蒜子等獨立庫時可以使用async屬性,若你的標簽必須寫在頭部內可以使用defer屬性
4. 兼容性那么,揣摩一下前輩的心理,同時寫上的原因是什么呢,兼容性?
上caniuse,async在IE<=9時不支持,其他瀏覽器OK;defer在IE<=9時支持但會有bug,其他瀏覽器OK;現象在這個issue里有描述,這也就是“望遠鏡”里建議只有一個defer的原因。所以兩個屬性都指定是為了在async不支持的時候啟用defer,但defer在某些情況下還是有bug。
5. 結論The defer attribute may be specified even if the async attribute is specified, to cause legacy Web browsers that only support defer (and not async) to fall back to the defer behavior instead of the synchronous blocking behavior that is the default.
其實這么講來,最穩妥的辦法還是把寫在底部,沒有兼容性問題,沒有白屏問題,沒有執行順序問題,高枕無憂,不要搞什么defer和async的花啦~
目前只研究了chrome的webkit的渲染機制,Firefox和IE的有待繼續研究,圖片和CSS以及其他外部資源的渲染有待研究。
更多信息在 這里
參考JavaScript高級程序設計
WebKit技術內幕
defer和async的區別
www.w3.org
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80262.html
摘要:相關腳本會立即下載并執行。從上面兩個例子,可以充分了解到標簽的柱塞式執行。表示該標簽并不柱塞,也不同步執行。屬性帶有屬性的腳本,同樣會推遲腳本的執行,并且不會阻止文檔解析。同時,帶有的腳本彼此之間,能保證其執行順序。 原文: http://pij.robinqu.me/Browser_Scripting/Document_Loading/ScriptTag.html 源...
摘要:阻塞原理瀏覽器內核可以分成兩部分渲染引擎或者和引擎。等引擎運行完畢,瀏覽器又會把控制權還給渲染引擎,繼續和的構建。執行時,解析暫停。從加載完成立即執行來看,模式執行順序與寫的順序無關,不保證執行順序。 js阻塞原理 瀏覽器內核可以分成兩部分:渲染引擎(Layout Engine 或者 Rendering Engine)和 JS 引擎。早期渲染引擎和 JS 引擎并沒有十分明確的區分,但隨...
摘要:緊接著發現,于是又停了,瀏覽器下載并執行完,繼續。,發現,遂將中文字展示了出來。的執行時間是在所有元素解析完成之后,事件觸發之前。的執行時間是在當前腳本下載完成后,所以多個是執行順序是不固定的。至此,完美的結構出爐了。 現代瀏覽器性能優化-JS篇 眾所周知,JS的加載和執行會阻塞瀏覽器渲染,所以目前業界普遍推薦把script放到之前,以解決js執行時找不到dom等問題。但隨著現代瀏覽器...
摘要:緊接著發現,于是又停了,瀏覽器下載并執行完,繼續。,發現,遂將中文字展示了出來。的執行時間是在所有元素解析完成之后,事件觸發之前。的執行時間是在當前腳本下載完成后,所以多個是執行順序是不固定的。至此,完美的結構出爐了。 現代瀏覽器性能優化-JS篇 眾所周知,JS的加載和執行會阻塞瀏覽器渲染,所以目前業界普遍推薦把script放到之前,以解決js執行時找不到dom等問題。但隨著現代瀏覽器...
摘要:盡管腳本的下載過程中不會相互影響,但頁面仍然要等到所有代碼下載并完成執行才能繼續。 defer和asnyc(只對外部文件有效) defer 在頁面完成解析時執行代碼,這個屬性表明腳本在執行時不會影響頁面的構造,在元素中設置這個屬性相當于告訴瀏覽器立即下載但延遲執行 async 相對于頁面其他部分異步執行腳本,一般的script標簽都是會阻塞頁面執行的,沒有加上async屬性的標簽...
閱讀 2123·2023-04-25 14:56
閱讀 2440·2021-11-16 11:44
閱讀 2696·2021-09-22 15:00
閱讀 1902·2019-08-29 16:55
閱讀 2177·2019-08-29 14:04
閱讀 2305·2019-08-29 11:23
閱讀 3678·2019-08-26 10:46
閱讀 1907·2019-08-22 18:43