JavaScript 文件的动态加载是你必须拥有的非常有用的工具之一。它允许你通过将阻塞脚本从加载过程中移出(通常称为“延迟加载”)来优化网页性能,并仅在用户需要时加载脚本(通常称为“按需加载”)。如果您明智地使用此工具,它将大大提高你的页面性能。
配置
让我们定义我们的示例模型,我们将从定义需要动态加载的远程文件开始。这是“ 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);
}
在上面的代码中,我们定义了一个立即函数来跟踪文件加载。我们还定义了一个从主页面调用的自定义函数。
现在,这是我们的主要“ index.htm
”页面。它只包含一个用于加载和测试文件的按钮。
<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>
元素中引用它。动态加载这个文件最简单的方法就是动态加载这个元素!(你没有看到即将到来吗?是吗?)
让我们更新代码并查看实际结果:
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);
};
上面的代码简单地创建了一个<script>
元素并将src
这个元素的字段设置为我们文件的路径。然后它使用该appendChild()
函数将其附加到我们代码的第一个子<head>
元素元素。以下代码产生以下结果:
现在,让我们重构上面的代码并稍微修改一下,以便能够在其他任何地方使用它:
/**
* 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");
});
};
现在,你可以轻松调用require()JavaScript 路径和回调函数,以便在加载脚本时收到通知。
费力方法
动态加载 JavaScript 文件的另一种方法是使用经典 HTTP 请求检索它。这是一个纯 JavaScript 调用,但它有很多缺点。让我们看看它的实际效果:
/**
* 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
设置一个 HTML 请求,然后触发它。然后,我们监控其状态变化并相应地执行。
当我们执行上面的代码时,我们得到以下结果。我们可以在 DevTools 扩展中看到我们成功的 XHR 请求:
另一方面,结果令人失望。我们能够成功运行脚本,并且 HTML 内容中没有脚本文件的线索,但是,由于eval()
的私有范围,我们无法调用加载的函数。
这种方式的其他缺点是它在跨域工作时会受到很大影响。而且你也不能从本地路径加载!
简单方法
现在是最直接的延迟加载 JavaScript 文件的方式,jQuery 方式。jQuery 提供了一个名为getScript()
(它是ajax()
的简写)的函数来检索和加载 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");
});
};
虽然在内部jQuery.getScript()
使用XMLHttpRequest
,并且您可以在 DevTools 中的 XHR 列表中看到请求,但它不会遭受与XMLHttpRequest
. 它比 raw
更容易使用和执行XMLHttpRequest
。
结果也很棒:
结论
总而言之,如果你在页面中启用了 jQuery,你就可以轻松地jQuery.getScript()
按需异步加载 JavaScript。如果你正在寻找一种纯 JavaScript 方法,请选择这种<script>
方法,它产生的开销很小。