外观
北京前端同事有个项目里用了ace-admin这个管理平台框架,不太喜欢这个框架,不过在里面发现了一段异步加载js脚本文件的代码,修改了一下贴到这里,以后自己项目里也可以用:
export function ready(optionalScriptsDependencies, cb) {
if (arguments.length === 1) {
waitForReady(cb);
} else if (arguments.length === 2) {
loadScripts(optionalScriptsDependencies, () => {
waitForReady(cb);
});
}
}
function waitForReady(cb) {
$(document).ready(function () {
cb && cb();
});
}
// ajaxLoadedScripts要放到loadScripts外才能起到全局统计的作用
const ajaxLoadedScripts = {};
function loadScripts(scripts, callback) {
$.ajaxPrefilter("script", (opts) => {
opts.cache = true;
});
setTimeout(() => {
function finishLoading() {
typeof callback === "function" && callback();
}
let deferredCount = 0;
let resolved = 0;
for (let i = 0; i < scripts.length; i++) {
if (scripts[i]) {
(() => {
const scriptName =
"js-" + scripts[i].replace(/[^\w\d-]/g, "-").replace(/--/g, "-");
ajaxLoadedScripts[scriptName] !== true && deferredCount++;
})();
}
}
function nextScript(index) {
index += 1;
if (index < scripts.length) {
loadScript(index);
} else {
finishLoading();
}
}
function loadScript(index) {
index = index || 0;
if (!scripts[index]) {
return nextScript(index);
}
const scriptName =
"js-" + scripts[index].replace(/[^\w\d-]/g, "-").replace(/--/g, "-");
// 只加载目前为止没有加载过的脚本
if (ajaxLoadedScripts[scriptName] !== true) {
$.getScript(scripts[index])
.done(() => {
ajaxLoadedScripts[scriptName] = true;
})
.complete(() => {
++resolved >= deferredCount ? finishLoading() : nextScript(index);
});
} else {
nextScript(index);
}
}
deferredCount > 0 ? loadScript() : finishLoading();
}, 10);
}使用方法很简单,碰到有js文件依赖的时候,这样使用ready方法:
ready(["../assets/js/jquery.validate.js"], () => {
// 这时依赖的js脚本文件已经加载完毕了,document ready后要执行的代码放在此处
});如果没有js文件依赖的话,这样使用ready方法:
ready(() => {
// document ready后要执行的代码放在此处
});下面是根据以前自己写过的方法封装一下得到的代码,作用差不多(没像上面的例子那样判断脚本是否已加载过,不过用document.write生成script标签加载js文件的话,浏览器自己也会做缓存处理的,问题不大吧-\_-):
function loadAsyncScripts(scripts, callback) {
const scriptsLength = scripts.length;
scripts.forEach((item) =>
loadAsyncScript(
item,
checkWhetherToExecuteCallback.bind(null, scriptsLength, callback),
),
);
}
let counter = 0;
function checkWhetherToExecuteCallback(scriptsLength, cb) {
++counter === scriptsLength && cb();
}
function loadAsyncScript(src, callback) {
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", src);
script.setAttribute("async", true);
script.setAttribute("defer", true);
head.appendChild(script);
if (document.all) {
script.onreadystatechange = function () {
var state = this.readyState;
if (state === "loaded" || state === "complete") {
callback();
}
};
} else {
script.onload = function () {
callback();
};
}
}