腳本的無阻塞加載
moduleA.js 代碼
console.log("I'm A");
/*
此處可以放jquery源碼
使得該文件變大,以便異步加載時看效果
*/
moduleB.js 代碼
console.log("I'm B");
同步加載
<body>
<script src="moduleA.js" onload="console.log('A loaded')"></script>
<script src="moduleB.js" onload="console.log('B loaded')"></script>
</body>
輸出
I'm A
A loaded
I'm B
A loaded
defer 和 async
defer
:在文檔完成解析後,觸發 DOMContentLoaded 事件前執行。如果缺少 src 屬性(即內嵌腳本),該屬性不應被使用,因爲這種情況下它不起作用。對動態嵌入的腳本使用 async=false
來達到類似的效果。
async
:是否在允許的情況下異步執行該腳本。該屬性對於內聯腳本無作用 (即沒有src屬性的腳本)。
defer 示例
<body>
<script defer src="moduleA.js" onload="console.log('A loaded')"></script>
<script src="moduleB.js" onload="console.log('B loaded')"></script>
</body>
輸出
I'm B
B loaded
I'm A
A loaded
async 示例
異步加載
<body>
<script>
loadScript("moduleA.js", "async A loaded");
loadScript("moduleB.js", "async B loaded");
function loadScript(url, text) {
var srcEle = document.createElement("script");
srcEle.src = url;
srcEle.async = true;
srcEle.onload = function () {
console.log(text);
};
document.body.appendChild(srcEle);
}
</script>
</body>
動態創建的script標籤,async默認爲true;
輸出
I'm B
async B loaded
I'm A
async A loaded
相同之處:
- 加載文件時不阻塞頁面渲染
- 使用這兩個屬性的腳本中不能調用document.write方法
- 有腳本的onload的事件回調
不同之處
- 每一個async屬性的腳本都在它下載結束之後立刻執行,同時會在window的load事件之前執行。所以就有可能出現腳本執行順序被打亂的情況;
- 每一個defer屬性的腳本都是在頁面解析完畢之後,按照原本的順序執行,同時會在document的DOMContentLoaded之前執行
AMD和CMD
AMD
RequireJS的標準
特點:依賴前置、預執行
define(['./a', './b'], function(a, b) {
//運行至此,a.js和b.js已經下載完成
//a模塊和b模塊已經執行完
a.doing();
b.doing();
});
CMD
SeaJS的標準
特點:依賴就近、懶執行
define(function(require, exports, module) {
var a = require("./a");
//等待a.js下載、執行完
a.doing();
var b = require("./b");
//等待b.js下載、執行完
b.doing();
});