Javascript 动态添加的脚本标记的加载顺序
我有一个typescript应用程序,可以动态添加指向JS文件的脚本标记。由于一些限制,我无法在html文件中静态定义这些脚本标记,因此我通过typescript动态添加它们,如下所示:Javascript 动态添加的脚本标记的加载顺序,javascript,html,typescript,load-order,Javascript,Html,Typescript,Load Order,我有一个typescript应用程序,可以动态添加指向JS文件的脚本标记。由于一些限制,我无法在html文件中静态定义这些脚本标记,因此我通过typescript动态添加它们,如下所示: for (let src of jsFiles) { let sTag = document.createElement('script'); sTag.type = 'text/javascript'; sTag.src = src; sTag.defer = true; document
for (let src of jsFiles) {
let sTag = document.createElement('script');
sTag.type = 'text/javascript';
sTag.src = src;
sTag.defer = true;
document.body.appendChild(script);
}
现在,我注意到,当我动态添加脚本标记时,它们似乎不能保证它们的加载顺序。不幸的是,jsFiles
数组中的脚本相互依赖。因此,数组中的第二个脚本只能在第一个脚本完全加载后加载。第二个脚本引用第一个脚本中定义的函数。是否有一种方法可以指定动态添加脚本时脚本的排序和执行顺序(类似于在html文件中静态定义脚本标记时的排序方式)
另外,我希望避免使用onload回调来解决这个问题,因为我注意到我的应用程序性能下降。我的第二个脚本文件非常大,我假设这是导致降级的原因 我可以提出一些替代方案来克服这一要求:
只需使用。ES2015:
导入
/导出
,或CommonJS:要求()
script
标记,并设置回调onload
,以便在异步加载脚本时做出反应。默认设置属性async=true
对象
或数组
XMLHttpRequest
),然后按照所需顺序使用脚本构建一个字符串
,最后通过setInterval
,检查脚本是否已经执行script
标记,并设置回调onload
,以便在异步加载脚本时做出反应
我想推荐一本关于脚本加载程序的书:,值得花半小时
以下示例是一个管理脚本注入的小模块,这是其基本思想:
let _scriptsToLoad = [
'path/to/script1.js',
'path/to/script2.js',
'path/to/script3.js'
];
function createScriptElement() {
// gets the first script in the list
let script = _scriptsToLoad.shift();
// all scripts were loaded
if (!script) return;
let js = document.createElement('script');
js.type = 'text/javascript';
js.src = script;
js.onload = onScriptLoaded;
let s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(js, s);
}
function onScriptLoaded(event) {
// loads the next script
createScriptElement();
};
在此plunker中,您可以按特定顺序异步测试脚本注入:
:接收要加载的每个脚本的URL或URL列表addScript
:运行任务以按指定顺序加载脚本load
:清除脚本数组,或取消脚本加载reset
:在加载每个脚本后执行回调afterLoad
:在加载所有脚本后执行回调onComplete
scriptsLoader
.reset()
.addScript("script1.js")
.addScript(["script2.js", "script3.js"])
.afterLoad((src) => console.warn("> loaded from jsuLoader:", src))
.onComplete(() => console.info("* ALL SCRIPTS LOADED *"))
.load();
在上面的代码中,我们首先加载“script1.js”
文件,并执行afterLoad()
回调,接下来,对“script2.js”
和“script3.js”
执行同样的操作,在加载所有脚本之后,执行onComplete()
回调
我希望避免使用onload回调来解决这个问题,因为我注意到我的应用程序性能下降
如果你想把文件整理好。。。您需要等待每个文件的onload。没办法
下面是我曾经写过的一个实用函数:
/**
* Utility : Resolves when a script has been loaded
*/
function include(url: string) {
return new Promise<{ script: HTMLScriptElement }>((resolve, reject) => {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.onload = function() {
resolve({ script });
};
document.getElementsByTagName('head')[0].appendChild(script);
});
}
/**
*实用程序:在加载脚本时解析
*/
函数包括(url:string){
返回新承诺((解决、拒绝)=>{
var script=document.createElement('script');
script.type='text/javascript';
script.src=url;
script.onload=函数(){
解析({script});
};
document.getElementsByTagName('head')[0].appendChild(脚本);
});
}
对于使用jQuery的任何人,我改进了@adeneo脚本,这样它将按指定顺序加载所有脚本。它不进行链式加载,因此速度非常快,但如果您想要更快,请更改50毫秒的等待时间
$.getMultiScripts = function(arr, path) {
function executeInOrder(scr, code, resolve) {
// if its the first script that should be executed
if (scr == arr[0]) {
arr.shift();
eval(code);
resolve();
console.log('executed', scr);
} else {
// waiting
setTimeout(function(){
executeInOrder(scr, code, resolve);
}, 50);
}
}
var _arr = $.map(arr, function(scr) {
return new Promise((resolve) => {
jQuery.ajax({
type: "GET",
url: (path || '') + scr,
dataType: "text",
success: function(code) {
console.log('loaded ', scr);
executeInOrder(scr, code, resolve);
},
cache: true
});
});
});
_arr.push($.Deferred(function( deferred ){
$( deferred.resolve );
}));
return $.when.apply($, _arr);
}
如何使用:
var script_arr = [
'myscript1.js',
'myscript2.js',
'myscript3.js'
];
$.getMultiScripts(script_arr, '/mypath/').done(function() {
// all scripts loaded
});
在普通的旧JS中,我会通过使用RequireJS使依赖项显式化来解决这个问题。然后每个脚本的主代码总是被包装,它们总是按照我想要的顺序执行,而不管上面的执行顺序如何。类似的方法也适用于你。如果项目很小,并且总是很小,那么可以在开始时添加一个非延迟脚本来管理执行顺序。然后,任何需要延迟执行的脚本都可以包装在一个函数中,该函数被传递到该控制脚本中。对defer属性有一些有用的注释。我相信有些库允许您异步下载文件,然后按顺序执行。请参阅RequireJS等。它们的性能比等待onload甚至开始下载下一个脚本要好得多。在2017年年中推荐RequireJS不是一个好建议。RequireJS已经过时,不再受支持——已经有几年了。查看Webpack、JSPM和Rollup.js作为更好的替代方案。或者script.js和loadjs在2019年这仍然是一种有效的方法,还是有更好的方法?引用的文章是2013年的,这在互联网上是很古老的。嗨@JoAMoS,不是,这个解决方案只适用于在浏览器中运行的旧项目。对于在TypeScript下运行的项目,Web