2016-12-01 120 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

你說得對。這是一個可能的解決方案。無論如何,我想知道這是否能以另一種方式完成......謝謝! –