JS異步那些事 五 (異步腳本加載)

JS異步那些事 一 (基礎知識)
JS異步那些事 二 (分佈式事件)
JS異步那些事 三 (Promise)
JS異步那些事 四(HTML 5 Web Workers)
JS異步那些事 五 (異步腳本加載)javascript

異步腳本加載

阻塞性腳本

JavaScript在瀏覽器中被解析和執行時具備阻塞的特性,也就是說,當JavaScript代碼執行時,頁面的解析、渲染以及其餘資源的下載都要停下來等待腳本執行完畢前端

瀏覽器是按照從上到下的順序解析頁面,所以正常狀況下,JavaScript腳本的執行順序也是從上到下的,即頁面上先出現的代碼或先被引入的代碼老是被先執行,即便是容許並行下載JavaScript文件時也是如此。注意咱們這裏標紅了"正常狀況下",緣由是什麼呢?咱們知道,在HTML中加入JavaScript代碼有多種方式,歸納以下(不考慮require.js或sea.js等模塊加載器):java

(1)正常引入:即在頁面中經過<script>標籤引入腳本代碼或者引入外部腳本
(2)經過document.write方法向頁面寫入<script>標籤或代碼
(3)經過動態腳本技術,即利用DOM接口建立<script>元素,並設置元素的src,而後再將元素添加進DOM中。
(4)經過Ajax獲取腳本內容,而後再建立<script>元素,並設置元素的text,再將元素添加進DOM中。
(5)直接把JavaScript代碼寫在元素的事件處理程序中或直接做爲URL的主體git

具體參考 http://www.jb51.net/article/77920.htmes6

腳本延遲運行

通常在JS頁面延遲執行一些方法。可使用如下的方法:github

Window.setTimeout  

jQuery.delay

jQuery.queue和jQuery.dequeue
<script src="deferdemo.js" defer></script>

加上 defer 等於在頁面徹底在入後再執行,至關於 window.onload ,但應用上比 window.onload 更靈活!segmentfault

<script type="text/javascript" src="demo_async.js" async="async"></script>

使用async屬性,瀏覽器會下載js文件,同時繼續對後面的內容進行渲染
一般若是js不須要改變DOM結構時可使用async進行異步加載(好比一些統計代碼能夠異步加載,由於此代碼與頁面執行邏輯無關,不會改變DOM結構)api

SeaJS與RequireJS

網上寫amd和cmd的文章不少,固然也有不少都是誤人子弟的片面的見解,因此仍是推薦本身看官方文檔多加嘗試去理解。瀏覽器

「RequireJS 遵循的是 AMD(異步模塊定義)規範,SeaJS 遵循的是 CMD (通用模塊定義)規範」。緩存

AMD 是 RequireJS 在推廣過程當中對模塊定義的規範化產出。
CMD 是 SeaJS 在推廣過程當中對模塊定義的規範化產出。

amd 規劃 https://github.com/amdjs/amdjs-api/wiki/AMD-(%E4%B8%AD%E6%96%87%E7%89%88)

cmd 規範 https://github.com/seajs/seajs/issues/242

區別:

  1. 對於依賴的模塊,AMD 是提早執行,CMD 是延遲執行。不過 RequireJS 從 2.0 開始,也改爲能夠延遲執行(根據寫法不一樣,處理方式不一樣)

  2. CMD 推崇依賴就近,AMD 推崇依賴前置。

ECMAScript6 Moudle

歷史上,JavaScript一直沒有模塊(module)體系,沒法將一個大程序拆分紅互相依賴的小文件,再用簡單的方法拼裝起來。其餘語言都有這項功能,好比Ruby的require、Python的import,甚至就連CSS都有@import
到了ES6,實現了模塊化的功能,功能上基本能夠取代 cmd和amd的規範,

模塊的功能主要由兩個命令構成,export和import,export命令用於規定模塊的對外接口,import命令用於輸入其餘模塊提供的功能。

export的寫法,

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {firstName, lastName, year};

上面代碼在export命令後面,使用大括號指定所要輸出的一組變量。

import寫法:

// main.js

import {firstName, lastName, year} from './profile';

function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}

ES6模塊加載的實質

ES6模塊加載的機制,與CommonJS模塊徹底不一樣。CommonJS模塊輸出的是一個值的拷貝,而ES6模塊輸出的是值的引用。CommonJS模塊輸出的是被輸出值的拷貝,也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值。

ES6模塊的運行機制與CommonJS不同,它遇到模塊加載命令import時,不會去執行模塊,而是隻生成一個動態的只讀引用。等到真的須要用到時,再到模塊裏面去取值,換句話說,ES6的輸入有點像Unix系統的」符號鏈接「,原始值變了,import輸入的值也會跟着變。所以,ES6模塊是動態引用,而且不會緩存值,模塊裏面的變量綁定其所在的模塊。

// 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,輸出的是一個C的實例。不一樣的腳本加載這個模塊,獲得的都是同一個實例。

// x.js
import {c} from './mod';
c.add();

// y.js
import {c} from './mod';
c.show();

// main.js
import './x';
import './y';

如今執行main.js,輸出的是1。
證實加載的是同一個實例
參考 http://es6.ruanyifeng.com/#docs/module

總結

寫這篇博客參考了不少網上的文章和一些書籍,由於太多就沒有一一列舉,這也算是我學習js異步知識的一個記錄吧。

畢竟立刻就要去以一個前端工程師的身份去鵝廠實習了,因此仍是要多學點東西,拿點乾貨出來。

關於JS異步那些事就寫到這裏了,不少地方理解的不夠深入但願你們多多指教。

相關文章
相關標籤/搜索