Javascript,按插入dom树的顺序执行脚本代码
不是重复的,因为我还没有在其他线程上找到满意的答案:Javascript,按插入dom树的顺序执行脚本代码,javascript,Javascript,不是重复的,因为我还没有在其他线程上找到满意的答案: 正在查找本机Javascript答案、无jQuery、无requireJS等等,请:) 整个问题的摘要: function loadScript(path, callback, errorCallback, options) { var element = document.createElement('script'); element.setAttribute("typ
正在查找本机Javascript答案、无jQuery、无requireJS等等,请:)
整个问题的摘要:
function loadScript(path, callback, errorCallback, options) {
var element = document.createElement('script');
element.setAttribute("type", 'text/javascript');
element.setAttribute("src", path);
return loadElement(element, callback, errorCallback, options);
}
function loadElement(element, callback, errorCallback, options) {
element.setAttribute("defer", "");
// element.setAttribute("async", "false");
element.loaded = false;
if (element.readyState){ // IE
element.onreadystatechange = function(){
if (element.readyState == "loaded" || element.readyState == "complete"){
element.onreadystatechange = null;
loadElementOnLoad(element, callback);
}
};
} else { // Others
element.onload = function() {
loadElementOnLoad(element, callback);
};
}
element.onerror = function() {
errorCallback && errorCallback(element);
};
(document.head || document.getElementsByTagName('head')[0] || document.body).appendChild(element);
return element;
}
function loadElementOnLoad(element, callback) {
if (element.loaded != true) {
element.loaded = true;
if ( callback ) callback(element);
}
}
loadScript("http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js",function() {
alert(1);
})
loadScript("http://ajax.googleapis.com/ajax/libs/chrome-frame/1.0.3/CFInstall.min.js",function() {
alert(2);
})
我想异步加载脚本,但已按顺序执行
我试图强制执行插入的脚本元素中的代码的执行顺序与添加到dom树中的顺序完全相同
也就是说,如果我插入两个脚本标记,第一个和第二个,第一个中的任何代码都必须在第二个之前触发,无论谁先完成加载
我试过在插入头部时使用async属性和defer属性,但似乎没有遵守
我已经尝试了element.setAttribute(“defer”和element.setAttribute(“async”,false)和其他组合
我目前遇到的问题是在包含外部脚本时必须执行,但这也是我在存在延迟的情况下执行的唯一测试
第二个脚本是本地脚本,它总是在第一个脚本之前触发,即使它是在dom树(head)中插入的
A) 注意我仍在尝试将这两个脚本元素插入DOM。当然,通过插入第一个,让它完成并插入第二个,可以实现上述目标,但我希望有另一种方法,因为这可能会很慢
我的理解是,RequireJS似乎正在这样做,所以这应该是可能的。然而,requireJS可能会通过按A)中所述的方式来实现
如果您想直接在firebug中尝试,只需复制并粘贴代码:
function loadScript(path, callback, errorCallback, options) {
var element = document.createElement('script');
element.setAttribute("type", 'text/javascript');
element.setAttribute("src", path);
return loadElement(element, callback, errorCallback, options);
}
function loadElement(element, callback, errorCallback, options) {
element.setAttribute("defer", "");
// element.setAttribute("async", "false");
element.loaded = false;
if (element.readyState){ // IE
element.onreadystatechange = function(){
if (element.readyState == "loaded" || element.readyState == "complete"){
element.onreadystatechange = null;
loadElementOnLoad(element, callback);
}
};
} else { // Others
element.onload = function() {
loadElementOnLoad(element, callback);
};
}
element.onerror = function() {
errorCallback && errorCallback(element);
};
(document.head || document.getElementsByTagName('head')[0] || document.body).appendChild(element);
return element;
}
function loadElementOnLoad(element, callback) {
if (element.loaded != true) {
element.loaded = true;
if ( callback ) callback(element);
}
}
loadScript("http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js",function() {
alert(1);
})
loadScript("http://ajax.googleapis.com/ajax/libs/chrome-frame/1.0.3/CFInstall.min.js",function() {
alert(2);
})
如果您像firebug一样尝试上面的代码,它通常会触发2,然后触发1。我想先确保1,然后确保2,但在头部包括这两个 您不能使用您的回调嵌套加载吗 即: 如果我插入两个脚本标记,第一个和第二个,第一个中的任何代码都必须在第二个之前触发,无论谁先完成加载。我试过使用async属性和defer属性 不,
async
和defer
在这里对您没有帮助。无论何时将脚本元素动态插入DOM,它们都会异步加载和执行。你不能做任何反对的事
我的理解是,RequireJS似乎正在这样做
不可以。即使使用RequireJS,脚本也是异步执行的,而且没有顺序。只有那些脚本中的模块初始化器函数才是define()
d,而不是执行。然后,Requirejs会查看它们的依赖关系何时得到满足,并在其他模块加载后执行它们
当然,你可以重新发明轮子,但你必须采用一种类似于requirejs的结构。经过一段时间的摆弄之后,我想到了这个。对脚本的请求会立即发出,但它们只能按指定的顺序执行 算法: 算法是维护一个需要执行的脚本树(我没有时间实现它:现在只是列表的退化情况)。所有这些请求几乎同时发送。每次加载脚本时,都会发生两件事:1)将脚本添加到已加载脚本的平面列表中;2)从根节点向下,执行每个分支中已加载但尚未执行的许多脚本 关于这一点,最酷的是,并非所有脚本都需要加载才能开始执行 实现: 出于演示目的,我在
scriptsToExecute
数组上反向迭代,以便CFInstall
请求在angularJS
请求之前发出。这并不一定意味着CFInstall
将在angularJS
之前加载,但这样做的可能性更大。不管怎样,angularJS
总是在CFInstall
之前进行评估
注意,就创建iframe元素和分配负载处理程序而言,我使用jQuery使我的工作更轻松,但您可以在不使用jQuery的情况下编写:
// The array of scripts to load and execute
var scriptsToExecute = [
"http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js?t=" + Date.now(),
"http://ajax.googleapis.com/ajax/libs/chrome-frame/1.0.3/CFInstall.min.js?t=" + Date.now()
];
// Loaded scripts are stored here
var loadedScripts = {};
// For demonstration purposes, the requests are sent in reverse order.
// They will still be executed in the order specified in the array.
(function start() {
for (var i = scriptsToExecute.length - 1; i >= 0; i--) {
(function () {
var addr = scriptsToExecute[i];
requestData(addr, function () {
console.log("loaded " + addr);
});
})();
}
})();
// This function executes as many scripts as it currently can, by
// inserting script tags with the corresponding src attribute. The
// scripts aren't reloaded, since they are in the cache. You could
// alternatively eval `script.code`
function executeScript(script) {
loadedScripts[script.URL] = script.code
while (loadedScripts.hasOwnProperty(scriptsToExecute[0])) {
var scriptToRun = scriptsToExecute.shift()
var element = document.createElement('script');
element.setAttribute("type", 'text/javascript');
element.setAttribute("src", scriptToRun);
$('head').append(element);
console.log("executed " + scriptToRun);
}
}
// This function fires off a request for a script
function requestData(path, loadCallback) {
var iframe = $("<iframe/>").load(function () {
loadCallback();
executeScript({
URL: $(this).attr("src"),
code: $(this).html()
});
}).attr({"src" : path, "display" : "none"}).appendTo($('body'));
}
//要加载和执行的脚本数组
var scriptsToExecute=[
"http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js?t=“+Date.now(),
"http://ajax.googleapis.com/ajax/libs/chrome-frame/1.0.3/CFInstall.min.js?t=“+Date.now()
];
//加载的脚本存储在这里
var loadedScripts={};
//出于演示目的,请求按相反顺序发送。
//它们仍将按照数组中指定的顺序执行。
(函数开始(){
对于(var i=scriptsToExecute.length-1;i>=0;i--){
(功能(){
var addr=scriptsToExecute[i];
请求数据(地址,函数(){
控制台日志(“已加载”+addr);
});
})();
}
})();
//此函数执行当前可以执行的尽可能多的脚本
//插入具有相应src属性的脚本标记。这个
//脚本不会重新加载,因为它们在缓存中。你可以
//或者eval`script.code`
函数executeScript(脚本){
loadedScripts[script.URL]=script.code
while(loadedScripts.hasOwnProperty(scriptsToExecute[0])){
var scriptToRun=scriptsToExecute.shift()
var-element=document.createElement('script');
setAttribute(“type”,“text/javascript”);
setAttribute(“src”,scriptToRun);
$('head')。追加(元素);
console.log(“已执行”+脚本运行);
}
}
//此函数用于发出脚本请求
函数requestData(路径、加载调用
function loadScript(order, path) {
var xhr = new XMLHttpRequest();
xhr.open("GET",path,true);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status >= 200 && xhr.status < 300 || xhr == 304){
loadedScripts[order] = xhr.responseText;
}
else {
//deal with error
loadedScripts[order] = 'alert("this is a failure to load script '+order+'");';
// or loadedScripts[order] = ''; // this smoothly fails
}
alert(order+' - '+xhr.status+' > '+xhr.responseText); // this is to show the completion order. Careful, FF stacks aletrs so you see in reverse.
// am I the last one ???
executeAllScripts();
}
};
}
function executeAllScripts(){
if(loadedScripts.length!=scriptsToLoad.length) return;
for(var a=0; a<loadedScripts.length; a++) eval(loadedScripts[a]);
scriptsToLoad = [];
}
var loadedScripts = [];
var scriptsToLoad = [
"http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js",
"http://ajax.googleapis.com/ajax/libs/chrome-frame/1.0.3/CFInstall.min.js",
"http://nowhere.existing.real_script.com.ar/return404.js"
];
// load all even in reverse order ... or randomly
for(var a=0; a<scriptsToLoad.length; a++) loadScript(a, scriptsToLoad[a]);
var stack = [];
stack.loaded = 0;
function loadScriptNew(path, callback) {
var o = { callback: callback };
stack.push(o);
loadScript(path, function() {
o.callbackArgs = arguments;
stack.loaded++;
executeWhenReady();
});
}
function executeWhenReady() {
if ( stack.length == stack.loaded ) {
while(stack.length) {
var o = stack.pop();
o.callback.apply(undefined, o.callbackArgs);
}
stack.loaded = 0;
}
}
function loadScript(path, callback) {
var element = document.createElement('script');
element.setAttribute("type", 'text/javascript');
element.setAttribute("src", path);
return loadElement(element, callback);
}
function loadElement(element, callback) {
element.setAttribute("defer", "");
// element.setAttribute("async", "false");
element.loaded = false;
if (element.readyState){ // IE
element.onreadystatechange = function(){
if (element.readyState == "loaded" || element.readyState == "complete"){
element.onreadystatechange = null;
loadElementOnLoad(element, callback);
}
};
} else { // Others
element.onload = function() {
loadElementOnLoad(element, callback);
};
}
(document.head || document.getElementsByTagName('head')[0] || document.body).appendChild(element);
return element;
}
function loadElementOnLoad(element, callback) {
if (element.loaded != true) {
element.loaded = true;
if ( callback ) callback(element);
}
}
loadScriptNew("http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js",function() {
alert(1);
});
loadScriptNew("http://ajax.googleapis.com/ajax/libs/chrome-frame/1.0.3/CFInstall.min.js",function() {
alert(2);
});