JavaScript 文件的動態(tài)加載是你必須擁有的非常有用的工具之一。它允許你通過將阻塞腳本從加載過程中移出(通常稱為“延遲加載”)來優(yōu)化網(wǎng)頁性能,并僅在用戶需要時(shí)加載腳本(通常稱為“按需加載”)。如果您明智地使用此工具,它將大大提高你的頁面性能。
配置
讓我們定義我們的示例模型,我們將從定義需要?jiǎng)討B(tài)加載的遠(yuǎn)程文件開始。這是“ ?remote.js
? ”文件的定義:
// this is going to be executed when script is loaded
(function () {
console.log("Remote script loaded");
}());
var sayHello = function (name) {
alert("Hello", name);
}
在上面的代碼中,我們定義了一個(gè)立即函數(shù)來跟蹤文件加載。我們還定義了一個(gè)從主頁面調(diào)用的自定義函數(shù)。
現(xiàn)在,這是我們的主要“ ?index.htm
? ”頁面。它只包含一個(gè)用于加載和測試文件的按鈕。
<html>
<head>
</head>
<body>
<button id="loadButton">Load script file</button>
<script type="text/javascript">
document.getElementById('loadButton').onclick = function () {
// your code goes here
};
</script>
</body>
</html>
無腦方法
加載 JavaScript 文件最直接的方法是在?<script>
?元素中引用它。動態(tài)加載這個(gè)文件最簡單的方法就是動態(tài)加載這個(gè)元素?。銢]有看到即將到來嗎?是嗎?)
讓我們更新代碼并查看實(shí)際結(jié)果:
document.getElementById("loadButton").onclick = function () {
var script = document.createElement("script");
script.src = "remote.js";
script.onload = function () {
sayHello("Mohammad");
};
// append and execute script
document.documentElement.firstChild.appendChild(script);
};
上面的代碼簡單地創(chuàng)建了一個(gè)?<script>
?元素并將?src
?這個(gè)元素的字段設(shè)置為我們文件的路徑。然后它使用該?appendChild()
?函數(shù)將其附加到我們代碼的第一個(gè)子?<head>
?元素元素。以下代碼產(chǎn)生以下結(jié)果:
現(xiàn)在,讓我們重構(gòu)上面的代碼并稍微修改一下,以便能夠在其他任何地方使用它:
/**
* Used to load and execute javascript file. an be used cross-domain seamlessly.
* @param file JS file name
* @param callback Subscribe to get notified when script file is loaded
**/
function require(file, callback) {
// create script element
var script = document.createElement("script");
script.src = file;
// monitor script loading
// IE < 7, does not support onload
if (callback) {
script.onreadystatechange = function () {
if (script.readyState === "loaded" || script.readyState === "complete") {
// no need to be notified again
script.onreadystatechange = null;
// notify user
callback();
}
};
// other browsers
script.onload = function () {
callback();
};
}
// append and execute script
document.documentElement.firstChild.appendChild(script);
}
document.getElementById("loadButton").onclick = function () {
require("remote.js", function () {
sayHello("Mohammad");
});
};
現(xiàn)在,你可以輕松調(diào)用require()JavaScript 路徑和回調(diào)函數(shù),以便在加載腳本時(shí)收到通知。
費(fèi)力方法
動態(tài)加載 JavaScript 文件的另一種方法是使用經(jīng)典 HTTP 請求檢索它。這是一個(gè)純 JavaScript 調(diào)用,但它有很多缺點(diǎn)。讓我們看看它的實(shí)際效果:
/**
* Used to load and execute javascript file. Suffers from same-domain restriction.
* @param file JS file name
* @param callback Subscribe to get notified when script file is loaded
**/
function requireXhr(file, callback) {
// object initialization
const xhr = new XMLHttpRequest();
// subscribe to request events
xhr.onreadystatechange = function () {
// readyState:
// 0 UNSENT Client has been created. open() not called yet.
// 1 OPENED open() has been called.
// 2 HEADERS_RECEIVED send() has been called, and headers and status are available.
// 3 LOADING Downloading; responseText holds partial data.
// 4 DONE The operation is complete.
// when not done, return
if (xhr.readyState !== 4) {
return;
}
// done, check status code
if (xhr.status !== 200) // 200 = OK
{
return;
}
// now the file is loaded,
// go and execute the script
eval(xhr.responseText);
// notify caller
if (callback) {
callback();
}
};
// open connection to file
xhr.open("GET", file, true);
// send the request
xhr.send();
}
document.getElementById("loadButton").onclick = function () {
requireXhr("remote.js", function () {
sayHello("Mohammad");
});
};
該代碼非常簡單且具有自我描述性。我們使用?XMLHttpRequestobject
?設(shè)置一個(gè) HTML 請求,然后觸發(fā)它。然后,我們監(jiān)控其狀態(tài)變化并相應(yīng)地執(zhí)行。
當(dāng)我們執(zhí)行上面的代碼時(shí),我們得到以下結(jié)果。我們可以在 DevTools 擴(kuò)展中看到我們成功的 XHR 請求:
另一方面,結(jié)果令人失望。我們能夠成功運(yùn)行腳本,并且 HTML 內(nèi)容中沒有腳本文件的線索,但是,由于?eval()
?的私有范圍,我們無法調(diào)用加載的函數(shù)。
這種方式的其他缺點(diǎn)是它在跨域工作時(shí)會受到很大影響。而且你也不能從本地路徑加載!
簡單方法
現(xiàn)在是最直接的延遲加載 JavaScript 文件的方式,jQuery 方式。jQuery 提供了一個(gè)名為?getScript()
?(它是?ajax()
?的簡寫)的函數(shù)來檢索和加載 JavaScript 文件。這是代碼:
/**
* Used to load and execute JavaScript file.
* @param file JS file name
* @param callback Subscribe to get notified when script file is loaded
**/
function requireAjax(file, callback) {
jQuery.getScript(file, callback);
}
document.getElementById("loadButton").onclick = function () {
requireAjax("remote.js", function () {
sayHello("Mohammad");
});
};
雖然在內(nèi)部?jQuery.getScript()
?使用?XMLHttpRequest
?,并且您可以在 DevTools 中的 XHR 列表中看到請求,但它不會遭受與?XMLHttpRequest
?. 它比 ?raw
?更容易使用和執(zhí)行?XMLHttpRequest
?。
結(jié)果也很棒:
結(jié)論
總而言之,如果你在頁面中啟用了 jQuery,你就可以輕松地??jQuery.getScript(?)
?按需異步加載 JavaScript。如果你正在尋找一種純 JavaScript 方法,請選擇這種?<script>
?方法,它產(chǎn)生的開銷很小。