JS異步那些事 一 (基礎(chǔ)知識(shí))
JS異步那些事 二 (分布式事件)
JS異步那些事 三 (Promise)
JS異步那些事 四(HTML 5 Web Workers)
JS異步那些事 五 (異步腳本加載)
異步腳本加載
阻塞性腳本
JavaScript在瀏覽器中被解析和執(zhí)行時(shí)具有阻塞的特性迎卤,也就是說(shuō)蜗搔,當(dāng)JavaScript代碼執(zhí)行時(shí),頁(yè)面的解析聘芜、渲染以及其他資源的下載都要停下來(lái)等待腳本執(zhí)行完畢
瀏覽器是按照從上到下的順序解析頁(yè)面缝龄,因此正常情況下,JavaScript腳本的執(zhí)行順序也是從上到下的服鹅,即頁(yè)面上先出現(xiàn)的代碼或先被引入的代碼總是被先執(zhí)行百新,即使是允許并行下載JavaScript文件時(shí)也是如此饭望。注意我們這里標(biāo)紅了"正常情況下",原因是什么呢厌漂?我們知道斟珊,在HTML中加入JavaScript代碼有多種方式,概括如下(不考慮require.js或sea.js等模塊加載器):
(1)正常引入:即在頁(yè)面中通過(guò)<script>標(biāo)簽引入腳本代碼或者引入外部腳本
(2)通過(guò)document.write方法向頁(yè)面寫(xiě)入<script>標(biāo)簽或代碼
(3)通過(guò)動(dòng)態(tài)腳本技術(shù)旨椒,即利用DOM接口創(chuàng)建<script>元素堵漱,并設(shè)置元素的src,然后再將元素添加進(jìn)DOM中示惊。
(4)通過(guò)Ajax獲取腳本內(nèi)容愉镰,然后再創(chuàng)建<script>元素丈探,并設(shè)置元素的text,再將元素添加進(jìn)DOM中糊肠。
(5)直接把JavaScript代碼寫(xiě)在元素的事件處理程序中或直接作為URL的主體
具體參考 http://www.jb51.net/article/77920.htm
腳本延遲運(yùn)行
一般在JS頁(yè)面延遲執(zhí)行一些方法∴托危可以使用以下的方法:
Window.setTimeout
jQuery.delay
jQuery.queue和jQuery.dequeue
<script src="deferdemo.js" defer></script>
加上 defer 等于在頁(yè)面完全在入后再執(zhí)行弧圆,相當(dāng)于 window.onload ,但應(yīng)用上比 window.onload 更靈活霹期!
<script type="text/javascript" src="demo_async.js" async="async"></script>
使用async屬性历造,瀏覽器會(huì)下載js文件船庇,同時(shí)繼續(xù)對(duì)后面的內(nèi)容進(jìn)行渲染
通常如果js不需要改變DOM結(jié)構(gòu)時(shí)可以使用async進(jìn)行異步加載(比如一些統(tǒng)計(jì)代碼可以異步加載,因?yàn)榇舜a與頁(yè)面執(zhí)行邏輯無(wú)關(guān)臣淤,不會(huì)改變DOM結(jié)構(gòu))
SeaJS與RequireJS
網(wǎng)上寫(xiě)amd和cmd的文章很多窃爷,當(dāng)然也有很多都是誤人子弟的片面的看法,所以還是推薦自己看官方文檔多加嘗試去理解医吊。
“RequireJS 遵循的是 AMD(異步模塊定義)規(guī)范遮咖,SeaJS 遵循的是 CMD (通用模塊定義)規(guī)范”造虏。
AMD 是 RequireJS 在推廣過(guò)程中對(duì)模塊定義的規(guī)范化產(chǎn)出麦箍。
CMD 是 SeaJS 在推廣過(guò)程中對(duì)模塊定義的規(guī)范化產(chǎn)出挟裂。
amd 規(guī)劃 https://github.com/amdjs/amdjs-api/wiki/AMD-(%E4%B8%AD%E6%96%87%E7%89%88)
cmd 規(guī)范 https://github.com/seajs/seajs/issues/242
區(qū)別:
對(duì)于依賴的模塊,AMD 是提前執(zhí)行栗竖,CMD 是延遲執(zhí)行。不過(guò) RequireJS 從 2.0 開(kāi)始添吗,也改成可以延遲執(zhí)行(根據(jù)寫(xiě)法不同份名,處理方式不同)
CMD 推崇依賴就近,AMD 推崇依賴前置鲤孵。
ECMAScript6 Moudle
歷史上辰如,JavaScript一直沒(méi)有模塊(module)體系,無(wú)法將一個(gè)大程序拆分成互相依賴的小文件鹰椒,再用簡(jiǎn)單的方法拼裝起來(lái)呕童。其他語(yǔ)言都有這項(xiàng)功能夺饲,比如Ruby的require、Python的import擂找,甚至就連CSS都有@import
到了ES6浩销,實(shí)現(xiàn)了模塊化的功能,功能上基本可以取代 cmd和amd的規(guī)范塘雳,
模塊的功能主要由兩個(gè)命令構(gòu)成普筹,export和import败明,export命令用于規(guī)定模塊的對(duì)外接口,import命令用于輸入其他模塊提供的功能太防。
export的寫(xiě)法妻顶,
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};
上面代碼在export命令后面,使用大括號(hào)指定所要輸出的一組變量。
import寫(xiě)法:
// main.js
import {firstName, lastName, year} from './profile';
function setName(element) {
element.textContent = firstName + ' ' + lastName;
}
ES6模塊加載的實(shí)質(zhì)
ES6模塊加載的機(jī)制讳嘱,與CommonJS模塊完全不同幔嗦。CommonJS模塊輸出的是一個(gè)值的拷貝,而ES6模塊輸出的是值的引用沥潭。CommonJS模塊輸出的是被輸出值的拷貝崭添,也就是說(shuō),一旦輸出一個(gè)值叛氨,模塊內(nèi)部的變化就影響不到這個(gè)值。
ES6模塊的運(yùn)行機(jī)制與CommonJS不一樣寞埠,它遇到模塊加載命令import時(shí)屁置,不會(huì)去執(zhí)行模塊,而是只生成一個(gè)動(dòng)態(tài)的只讀引用仁连。等到真的需要用到時(shí)蓝角,再到模塊里面去取值,換句話說(shuō)饭冬,ES6的輸入有點(diǎn)像Unix系統(tǒng)的”符號(hào)連接“使鹅,原始值變了,import輸入的值也會(huì)跟著變昌抠。因此患朱,ES6模塊是動(dòng)態(tài)引用,并且不會(huì)緩存值炊苫,模塊里面的變量綁定其所在的模塊裁厅。
// mod.js
function C() {
this.sum = 0;
this.add = function () {
this.sum = 1;
};
this.show = function () {
console.log(this.sum);
}
}
export let c = new C();
上面的腳本mod.js,輸出的是一個(gè)C的實(shí)例侨艾。不同的腳本加載這個(gè)模塊执虹,得到的都是同一個(gè)實(shí)例。
// x.js
import {c} from './mod';
c.add();
// y.js
import {c} from './mod';
c.show();
// main.js
import './x';
import './y';
現(xiàn)在執(zhí)行main.js唠梨,輸出的是1袋励。
證明加載的是同一個(gè)實(shí)例
參考 http://es6.ruanyifeng.com/#docs/module
總結(jié)
寫(xiě)這篇博客參考了很多網(wǎng)上的文章和一些書(shū)籍,因?yàn)樘嗑蜎](méi)有一一列舉当叭,這也算是我學(xué)習(xí)js異步知識(shí)的一個(gè)記錄吧茬故。
畢竟馬上就要去以一個(gè)前端工程師的身份去鵝廠實(shí)習(xí)了,所以還是要多學(xué)點(diǎn)東西科展,拿點(diǎn)干貨出來(lái)均牢。
關(guān)于JS異步那些事就寫(xiě)到這里了糠雨,很多地方理解的不夠深刻希望大家多多指教才睹。