2016-12-01 75 views
0

我有一个基本的SPA,它可以根据需要加载一些资源(主要是样式表和脚本)。控制动态加载脚本的加载顺序

加载程序是这样的(这是一个简化版本):

class ModuleXLoader 
    constructor: -> 
     @scripts = [ 
      'https://www.example.com/assets/js/script1.js', 
      'https://www.example.net/assets/js/script2.js', 
      'https://www.example.org/assets/js/script3.js' 
     ] 
     @scriptsLoaded = 0 

    load: (@callback) -> 
     document.head.appendChild @.scriptTag url for url in @scripts 

    scriptTag: (url) -> 
     domElement = document.createElement 'script' 
     domElement.type = 'text/javascript' 
     domElement.onload = (event) => 
      console.log event.currentTarget.srC# This logs the script's URL 
      @.callback() if [email protected] is @scripts.length and typeof @callback is 'function' 
     domElement.src = url 
     return domElement 

所以,当我需要加载ModuleX我做的:

loader = new ModuleXLoader() 
loader.load() => 
    console.log 'All scripts have been loaded, let\'s do stuff!' 

这追加所需的脚本我<head>一切都按预期工作。


问题当有需要的脚本之间的一些依赖出现。根据每个CDN的响应时间(比方说example.comexample.net ...)脚本在随机顺序加载所以,有时我得到了经典:

Uncaught ReferenceError: ModuleXDependency is not defined

当然,我尝试了不同的ordenations我@scripts数组,但它并不重要。

我想对某种信号灯实现:

@scripts = 
    script1: 
     url: 'https://www.example.com/assets/js/script1.js' 
     requires: 'script3' 
     loaded: false 
    script2: # etc. 


domElement.onload = (event) => 
    # This is not a real implementation but kind of pseudocode idea... 
    @wait() while not @scripts[@scripts['script1'].requires].loaded 

但说实话感觉太肮脏走这条路,所以我想知道是否也许有人有更好的主意......

+0

使用AMD我不是假设你的选择吗?其他一切可能会影响性能。但方法很清楚:构建一个依赖关系图并进行处理。动态添加的脚本在不同的浏览器中执行的方式不同。但是他们可能会执行'async',所以无法控制它。 – Lux

+0

嗨@Lux,我不熟悉AMD。你能提供一些文件的链接吗? –

回答

3

我的建议是使用模块定义,如AMD。也许你应该考虑使用现有的模块加载器,如requirejs。您还可以在这里找到关于AMD的文档。也许阅读whyAMD文本。

如果你想要一个绝对最小的加载器并自己加载脚本,你可以结账loader.js

关于AMD的想法是基本上是定义你的模块,像这样:

define('dep', [], function() { 
    // here goes your code 
    return {}; 
}); 

define('mymodule', ['dep'], function(dep) { 
    // here goes your code. 
}); 

loader.jsrequire.js加载器将基本建成,这些模块的图形,然后当你这样做require('mymodule')它会知道它必须首先调用dep,然后将结果作为第一个参数注入mymodule

loader.js基本上只是做到这一点,而require.js有能力通过网络加载模块。

但是,既可以手动加载脚本标记,等到所有加载脚本标记,然后调用您的入口点。

重要的是,执行define调用的顺序并不重要。

1

一个解决方案是创建捆绑包,只需将您要同时加载的所有依赖关系连接到一个缩小的js文件“捆绑”中。加载一个文件而不是3.它将解决你的依赖顺序问题,并提供其他改进。

+0

你说得对。这是一个可能的解决方案。无论如何,我想知道这是否能以另一种方式完成......谢谢! –