我有一个概念验证适用于JavaScript自动加载器,但它目前存在一个主要缺陷:它需要完整地重新执行代码,而不是简单地从失败的行再次尝试。
这是原型:
<!doctype html>
<html>
<head>
</head>
<body>
<script type="text/javascript">
var app = function(){
console.log('Initialize App');
var test = new Test();
var foo = new Foo();
var bar = new Bar();
};
var autoload = function(app){
var recover = function(error){
var name = error.message.split(' ')[0];
console.log('Loading '+name);
//A file could be synchronously loaded here instead
this[name] = function(){
console.log(name+' has been dynamically created');
};
load(app);
};
var load = function(app){
try {
app();
} catch (error){
if (error.name == "ReferenceError"){
console.log(error.message);
recover(error, app);
}
}
};
load(app);
};
autoload(app);
</script>
</body>
</html>
如何工作
我们的想法是,所有应用程序代码都将在app
函数中执行。最后,如果我可以正常工作,您还可以使用app函数将依赖关系映射传递给自动加载器,以便在未定义函数时同步加载依赖关系。依赖关系图只是将函数名称映射到文件名的对象。
目前如何运作
如果您不想尝试,请输入以下代码:
Initialize App
Test is not defined
Loading Test
Initialize App
Test has been dynamically created
Foo is not defined
Loading Foo
Initialize App
Test has been dynamically created
Foo has been dynamically created
Bar is not defined
Loading Bar
Initialize App
Test has been dynamically created
Foo has been dynamically created
Bar has been dynamically created
每次自动加载器捕获错误时,都会重新执行完整的app
函数。显然,出于多种原因,这不太理想。
从错误中恢复
要进入下一步使这项工作,我需要找到一种从错误中恢复的方法,而无需重新执行整个app
函数。来自error
块的catch
对象确实提供了发生错误的行号和文件名,但到目前为止,我还未能找到利用该信息的方法。我能想到三种一般方法:
eval
分开。不幸的是,我无法找到前两种方法中的任何一种方法的信息。在这三者中,#1看起来似乎更理想,但我肯定会接受其他创意建议。据我所知,JavaScript没有提供一种在任意行号下启动脚本执行的方法。 #3 可能工作,但我不确定它是否会非常高效。我能想到的唯一方法就是每次都要求额外的请求将文件文本加载到字符串中。
问题
这无疑推动了如何在JavaScript中加载依赖关系的界限。我甚至不确定它是否可行,因为我不知道JavaScript是否允许这种类型的错误恢复。也就是说,我有兴趣进一步探索它,直到我发现它绝对不可能。
为了让这项工作成功:
退一步看看更大的图片(假设我可以让它工作):
答案 0 :(得分:0)
制作起来很复杂,投掷和捕捉也很贵。您可以使用typeof window["Test"]!=="function"
然后创建它而不是像这样使用try catch。
但是对于一般的恢复和继续方法,下面的代码可以解决问题。
var app = (function(i){
var objects=new Array(3),
fnNames=["Test","Foo","Bar"];
return function(){
var len=fnNames.length
,test,foo,bar;
//check if closure vars have been reset, if so
// this has ran successfully once so don't do anything?
if(objects===false){
console.log("nothing to do, initialized already");
return;
}
while(i<len){
try{
objects[i] = new window[fnNames[i]]();
i++;
}catch(e){
if (e.name == "TypeError"){//different syntax different error
throw {"fnName":fnNames[i]};
}
}
}
//store instances in the variables
test = objects[0];
foo = objects[1];
bar = objects[2];
//reset closure vars assuming you only call app once
// when it's successful
i=null;objects=false;
console.log("Got all the instances",test,foo,bar);
};
}(0));
var autoload = function(app){
var recover = function(name){
console.log('Loading '+name);
//A file could be synchronously loaded here instead
this[name] = function(){
this.name=name;
console.log(this.name+' has been dynamically created');
};
load(app);
};
var load = function(app){
try {
app();
} catch (error){
//if statement here no longer needed
// object thrown has fnName (function name)
recover(error.fnName, app);
}
};
load(app);
};
autoload(app);
autoload(app);