转发
我注意到这个问题是一个"功能范围 - 不阻止范围"回答,差异是for ... in
反对for ... i<n ... i++
解决方案可能是使用函数包装for(var p in ...) {
以赋予它们自己的范围(就像使用Array.prototype.forEach
一样)。谢谢您的帮助。
问题
我正在使用我自己的小型Require.js解决方案,而不是实际的Require.js库(不,我没有看过他们的来源)。
我的回调函数似乎永远不会执行,但我无法弄清楚原因。这可能是一个简单的逻辑错误,但是当你长时间盯着自己的代码时,你知道它是怎么回事。 (一切看起来都很合理)
用法
使用如下:
require(["LibraryA", "LibraryB", "LibraryC"], function() {
//code which requires libraries a-c here
});
代码
var require = (function() {
var scriptsLoaded = [];
return function(paths, callback) {
var pathsDoneLoading = {};
for(var i = 0; i < paths.length; i++) {
pathsDoneLoading[paths[i]] = false;
}
for(var p in pathsDoneLoading) {
for(var i = 0; i < scriptsLoaded.length; i++) {
if(p === scriptsLoaded[i]) {
pathsDoneLoading[p] = true;
}
}
}
for(var p in pathsDoneLoading) {
if(pathsDoneLoading[p] === false) {
var script = document.createElement("script");
script.src = p + ".js";
script.onload = function() {
scriptsLoaded.push(p);
pathsDoneLoading[p] = true;
for(var p in pathsDoneLoading) {
if(pathsDoneLoading[p] !== true) {
return;
}
}
callback();
};
document.documentElement.appendChild(script);
}
}
}
})();
Plunker
答案 0 :(得分:2)
这是旧的for
循环变量捕获问题。
在循环中,它正在迭代加载的路径(for (var p in pathsDoneLoading) {
),p
被绑定到里面的函数。问题是p
在循环完成后会发生变化并持续存在,因此每个函数都会将pathsDoneLoading
对象中的 last 键添加到scriptsLoaded
数组中(并将pathsDoneLoading
中的匹配值设置为true
)。
问题的一个例子:
var obj = { a: 1, b: 2, c: 3 };
var funcs = [];
for (var key in obj) {
funcs.push(function() {
return key; // Remember, `key` is bound to the function, not the block
});
}
funcs.forEach(function(f) {
document.querySelector('pre').innerText += f() + '\n';
});
<pre></pre>
要解决此问题,您可以将其包装在IIFE中,以便按p
值创建新的绑定。
for (var p in pathsDoneLoading) {
(function(p) {
if (pathsDoneLoading[p] === false) { // or `if (!pathsDoneLoading[p])`
...
})(p);
}
这样每次生成onload
处理程序时,它们都具有与预期路径的唯一绑定。
我们之前的示例已使用此解决方案修复:
var obj = { a: 1, b: 2, c: 3 };
var funcs = [];
for (var key in obj) {
(function(key) {
funcs.push(function() {
return key; // Remember, `key` is bound to the function, not the block
});
})(key);
}
funcs.forEach(function(f) {
document.querySelector('pre').innerText += f() + '\n';
});
<pre></pre>
答案 1 :(得分:0)
简单地说,你需要捕获for循环迭代器,因为它是一个移动的目标,并且当onload触发时,它会发生变化。
var require = (function() {
var scriptsLoaded = [];
return function(paths, callback) {
var pathsDoneLoading = {};
for(var i = 0; i < paths.length; i++) {
pathsDoneLoading[paths[i]] = false;
}
for(var p in pathsDoneLoading) {
for(var i = 0; i < scriptsLoaded.length; i++) {
if(p === scriptsLoaded[i]) {
pathsDoneLoading[p] = true;
}
}
}
for(var p in pathsDoneLoading) {
if(pathsDoneLoading[p] === false) {
var script = document.createElement("script");
script.src = p + ".js";
// Wrapping in a closure
script.onload = (function(Vp) {
scriptsLoaded.push(Vp);
pathsDoneLoading[Vp] = true;
for(var prop in pathsDoneLoading) {
if(pathsDoneLoading[prop] !== true) {
return;
}
}
callback();
// Execute the closure function and send in your
// var(s) as argument(s) to capture it's current state
}(p));
document.documentElement.appendChild(script);
}
}
}
})();