script的defer和async
我們常用的script標簽,有兩個和性能、js文件下載執(zhí)行相關(guān)的屬性:defer和async
defer的含義【摘自https://developer.mozilla.org/En/HTML/Element/Script】
This Boolean attribute is set to indicate to a browser that the script is meant to be executed after the document has been parsed.
async的含義【摘自https://developer.mozilla.org/En/HTML/Element/Script】
Set this Boolean attribute to indicate that the browser should, if possible, execute the script asynchronously.
?
Defer
對于defer,我們可以先思考一個情況。一個頁面如果有N個外鏈的腳本,放在head中,那么,當加載腳本時會阻塞頁面的渲染,也就是常說的空白。在簡單的開發(fā)環(huán)境中,我們可能只要將源代碼中的外鏈腳本位置換一下就ok了。可是面對越來越復(fù)雜的開發(fā)環(huán)境,前端同事如果要后臺開發(fā)同事調(diào)整一下腳本的位置,可能會花費大量的溝通成本和開發(fā)成本。我在去年的一個項目中就遇到過此類情況,當然也很感謝當時的后臺開發(fā)同事的配合,他們都辛辛苦苦的調(diào)整了腳本的位置,解決了空白的問題。
?
那么可以讓這個成本降到最低嗎?那么我們可以使用defer這個屬性。
如果一個script加了defer屬性,即使放在head里面,它也會在html頁面解析完畢之后再去執(zhí)行,也就是類似于把這個script放在了頁面底部。
關(guān)于defer有兩個demo:
- without defer
- with defer
簡單介紹一下這個demo,一共引用了3個js和1個css,為了能更好的展示defer的效果,第二個js-2.php是延遲了3秒返回的。1.js會在頁面中生成一個值為1的input框,2.php會生成值為2的input框,3.js會生成值為3的input框。一方面我們需要觀察頁面渲染的時間,另一方面我們也要看一下js是否順序執(zhí)行了。
下圖是without_defer.html的效果,從瀑布圖可以看出,domready和onload的時間都在6s左右,因為需要等待2.php的返回才能渲染頁面。如果你訪問上面的例子,可以看出,頁面要等6s的時間才會呈現(xiàn)出來,6s之前都是空白。
那么如果我們?yōu)槊總€js都加上defer屬性,請看下面兩張圖
第一張是在加載過程中截取的,可以看到一旦有了defer屬性,雖然有資源2.php需要等待,但是仍然會繼續(xù)渲染頁面,加載后續(xù)的js和css等資源文件。對比上面的情況,可以看到domready的時間明顯提前,如果你訪問demo地址,會發(fā)現(xiàn)頁面會照常渲染出來,只不過2.php里面的內(nèi)容會延遲執(zhí)行。
從上面的對比可以看出,對于defer,我們可以認為是將外鏈的js放在了頁面底部。js的加載不會阻塞頁面的渲染和資源的加載。不過defer會按照原本的js的順序執(zhí)行,所以如果前后有依賴關(guān)系的js可以放心使用。
?
Async
對于async,這個是html5中新增的屬性,它的作用是能夠異步的加載和執(zhí)行腳本,不因為加載腳本而阻塞頁面的加載。一旦加載到就會立刻執(zhí)行。那async和defer有什么不同之處呢?我們還是先看async的兩個demo
- without async
- with async
demo的效果和上面描述的一樣。
下圖是without async的瀑布圖,和沒有defer的情況是一樣的。domready和load的時間都因為一個js的延遲而延遲了。
我們再看一下有async屬性的情況,和defer一樣,會等待的資源不會阻塞其余資源的加載,也不會影響頁面的加載。但是有一點需要注意下,在有async的情況下,js一旦下載好了就會執(zhí)行,所以很有可能不是按照原本的順序來執(zhí)行的。如果js前后有依賴性,用async,就很有可能出錯。
?
Difference
這篇文章中總結(jié)了defer和async的相同點和區(qū)別。
Both?async?and?defer?scripts begin to download immediately without pausing the parser and both support an optional onload handler to address the common need to perform initialization which depends on the script. The difference between?async?and?defer?centers around when the script is executed. Each?async?script executes at the first opportunity after it is finished downloading and before the window’s load event. This means it’s possible (and likely) thatasync?scripts are not executed in the order in which they occur in the page. The?defer?scripts, on the other hand, are guaranteed to be executed in the order they occur in the page. That execution starts after parsing is completely finished, but before the document’sDOMContentLoaded?event.
?
Wrapping it up
在上述的基礎(chǔ)上,我根據(jù)實際使用的情況總結(jié)了一下defer和async的特征。
相同點:
- 加載文件時不阻塞頁面渲染
- 對于inline的script無效
- 使用這兩個屬性的腳本中不能調(diào)用document.write方法
- 有腳本的onload的事件回調(diào)
區(qū)別點:
- html的版本html4.0中定義了defer;html5.0中定義了async
- 瀏覽器
FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari Basic support 1.0 1.0 (1.7 or earlier) (Supported) (Supported) (Supported) asyncattribute (Supported) 3.6 (1.9.2) 10 – (Supported) deferattribute (Supported) 3.5 (1.9.1) 4 – (Supported) - 執(zhí)行時刻
每一個async屬性的腳本都在它下載結(jié)束之后立刻執(zhí)行,同時會在window的load事件之前執(zhí)行。所以就有可能出現(xiàn)腳本執(zhí)行順序被打亂的情況;每一個defer屬性的腳本都是在頁面解析完畢之后,按照原本的順序執(zhí)行,同時會在document的DOMContentLoaded之前執(zhí)行。
摘自【http://dev.w3.org/html5/spec/Overview.html#attr-script-async】
There are three possible modes that can be selected using these attributes. If the async attribute is present, then the script will be executed asynchronously, as soon as it is available. If the async attribute is not present but the defer attribute is present, then the script is executed when the page has finished parsing. If neither attribute is present, then the script is fetched and executed immediately, before the user agent continues parsing the page.
簡單的來說,使用這兩個屬性會有三種可能的情況
- 如果async為true,那么腳本在下載完成后異步執(zhí)行。
- 如果async為false,defer為true,那么腳本會在頁面解析完畢之后執(zhí)行。
- 如果async和defer都為false,那么腳本會在頁面解析中,停止頁面解析,立刻下載并且執(zhí)行,
最后給一點個人的建議,無論使用defer還是async屬性,都需要首先將頁面中的js文件進行整理,哪些文件之間有依賴性,哪些文件可以延遲加載等等,做好js代碼的合并和拆分,然后再根據(jù)頁面需要使用這兩個屬性。
本文another鏈接:http://feifeipan.sinaapp.com/?p=51
=====華麗麗的分割線=========
對于znxds提出的IE下的工作,我針對FF和IE6、IE7、IE8下面做了比較。
demo
Firefox中,inline的defer是沒有效果的;outer的defer會在頁面最底部執(zhí)行。
?
IE8.0中,inline和outer的defer是起作用的,都會延遲到頁面底部,排在其他非defer的js后面執(zhí)行
IE7.0的情況,和IE8.0一致。
IE6.0中,關(guān)于defer inline js,要區(qū)分是在head中還是在body中。在head中defer inline js會在遇到body之后優(yōu)先執(zhí)行,而在body中的defer inline js會在body結(jié)束之前執(zhí)行;關(guān)于defer outer js, 依然是在頁面最后執(zhí)行。
所以可以看出,defer的outer js在各種瀏覽器中表現(xiàn)一致;defer的inline js在IE6中比較特殊,head和body中的順序不一樣,IE7和IE8會延遲到頁面底部執(zhí)行,在Firefox中無效。
本文作者:小灰灰 轉(zhuǎn)載請注明來自:攜程UED
轉(zhuǎn)載于:https://www.cnblogs.com/human/p/3419737.html
總結(jié)
以上是生活随笔為你收集整理的script的defer和async的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 使用XmlPullPar
- 下一篇: 静态成员变量和静态成员函数(static