2016-01-13 75 views
2

正向我自己的滚动需要

它已经到了我的注意,这个问题是一个“函数的范围, - 不阻塞作用域”的答案,不同之处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

https://plnkr.co/edit/OFWTUpmV3sIJAjhGhcLO

+0

在创建所有脚本元素后,不应该调用回调吗?现在看起来你想在每个脚本加载后调用它 –

+1

你正在将'require'定义为一个自动执行的方法吗?考虑到放弃后面的'();' – Sean3z

+0

我的想法是,“如果其中一个路径没有完成就返回”,这导致我假设“如果我们在这里做出默认回调” –

回答

2

这是旧的for循环变量捕捉问题。

在循环中,它正在迭代正在加载的路径(for (var p in pathsDoneLoading) {),p正在绑定到里面的函数。的问题是,p改变和仍然存在的回路具有完整所以每单功能是增加在pathsDoneLoading对象的最后关键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>

0

简单地说,你需要捕捉的循环迭代,因为它是一个移动的目标和时间的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); 
      } 
     } 
    } 
})(); 
+0

感谢您的回答。顺便说一下,当你调用'onload' IIFE,并且你的'(p)'参数语法不正确时,你没有返回任何东西,但是我在其他代码中实现了这个解决方案,并且它工作正常。 –

+0

很酷。只是试图让事情变得简单,而不是覆盖原来的代码。 Javascript是相当宽容的。要关注的一点是Vp关系。 – bob

相关问题