>我有以下函数来加载给定的脚本:
function addScriptTag(url){
var script = document.createElement('script');
script.src = url;
document.getElementsByTagName('head')[0].appendChild(script);
}
我使用该函数加载彼此相关的库,其中lib2
依赖于lib1
,lib1
取决于jquery
:
function loadThemAll(){
addScriptTag('http://path/to/jquery.js');
addScriptTag('http://path/to/lib1.js');
addScriptTag('http://path/to/lib2.js');
}
问题是,即使按照这个顺序,当lib1
需要jQuery时,它也找不到它。这同样适用于使用lib1
的lib2
。
如何使脚本标签按顺序创建和加载脚本? 换句话说:
为jQuery
添加脚本标记并加载它。
加载jQuery
后,添加lib1
的脚本标记并加载它。
加载lib1
后,添加lib2
的脚本标记并加载它。
在尝试加载下一个脚本之前,您不会等待上一个脚本加载,您可以尝试使用Promises
和脚本元素的onload
回调。
function addScriptTag(url) {
return new Promise(function (resolve, reject) {
var script = document.createElement('script');
script.onload = resolve;
script.onerror = reject;
script.src = url;
document.getElementsByTagName('head')[0].appendChild(script);
})
}
addScriptTag('http://path/to/jquery.js').then(function() {
return addScriptTag('http://path/to/lib1.js');
}).then(function() {
return addScriptTag('http://path/to/lib2.js');
});
由于新脚本的onload
方法设置为返回的Promise
addScriptTag
的解析,这应该会导致脚本等到加载前一个脚本。
您可以更进一步,编写一个函数,该函数需要按顺序加载脚本列表:
function loadScripts(scripts, promise) {
if (!promise) {
promise = new Promise();
}
script = scripts.shift();
if (script) {
addScriptTag(script).then(function () {
loadScripts(scripts, promise);
}).catch(function () {
promise.reject();
});
} else {
promise.resolve();
}
return promise;
}
loadScripts([
'http://path/to/jquery.js',
'http://path/to/lib1.js',
'http://path/to/lib2.js'
]).then(function () {
console.log("Scripts loaded");
});
addScriptTag
返回一个在加载脚本时解析的 Promise,并await
每次调用:
function addScriptTag(url){
return new Promise((resolve, reject) => {
var script = document.createElement('script');
script.addEventListener('load', resolve);
script.addEventListener('error', reject);
script.src = url;
document.head.appendChild(script);
});
}
async function loadThemAll(){
await addScriptTag('http://path/to/jquery.js');
await addScriptTag('http://path/to/lib1.js');
await addScriptTag('http://path/to/lib2.js');
}
loadThemAll()
.then(() => {
console.log('Everything is loaded!');
})
.catch((err) => {
console.log('There was a problem:', err);
});
您也可以使用async=false
,但这会在脚本加载之前阻止,因此可能不是一个好主意:
function addScriptTag(url){
var script = document.createElement('script');
script.setAttribute('async', 'false');
script.src = url;
document.head.appendChild(script);
}
function loadThemAll(){
addScriptTag('http://path/to/jquery.js');
addScriptTag('http://path/to/lib1.js');
addScriptTag('http://path/to/lib2.js');
}
您可以将defer
属性添加到脚本中。有关更多详细信息,请参阅此问题