我有一个基本的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 ++@scriptsLoaded 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.com
,example.net
...)脚本以随机顺序加载,因此,有时我得到了经典:
未捕获的ReferenceError:未定义 ModuleXDependency
当然,我在我的@scripts
数组上尝试了不同的ordenations,但它并不重要。
我正在考虑某种信号量实现:
@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 :(得分:3)
我的建议是使用像AMD
这样的模块定义。也许您应该考虑使用像requirejs这样的现有模块加载器。您还可以在此处找到有关AMD
的文档。也许请阅读whyAMD文字。
如果你想要一个absolut最小的加载器并自己加载脚本,你可以结帐loader.js
。
关于AMD的想法基本上是你定义你的模块:
define('dep', [], function() {
// here goes your code
return {};
});
define('mymodule', ['dep'], function(dep) {
// here goes your code.
});
像loader.js
或require.js
这样的加载器基本上会构建这些模块的图形,然后当您执行类似require('mymodule')
的操作时,它会知道它必须调用dep
首先,然后将结果作为第一个参数注入mymodule
。
loader.js
基本上只会执行此操作,而require.js
则可以通过网络加载模块。
然而,两者都可以手动加载脚本标记,等待所有加载,然后调用入口点。
重要的是,执行define
的调用的顺序无关紧要。
答案 1 :(得分:1)
一种解决方案是创建捆绑包,只需将您将同时加载的所有依赖项连接到一个缩小的js文件,即&#34;捆绑包&#34;。加载一个文件而不是3.它将解决您的依赖顺序问题,并提供其他改进。