2017-02-18 5 views
0

が、私は動的にJSのスクリプトをロードするには、かなり標準loadScript方法を持っている、と行われたときに、コールバックが発射される:私のプロジェクトの状況ではJSスクリプトを並行処理で安全に動的にロードするには?私のプロジェクトで

app.utilities.loadScript = function loadScript(url, callback) 
{ 

    if (app.scripts[url]===true) { 
    callback(); 
    } else { 

    var head = document.getElementsByTagName('head')[0]; 
    var script = document.createElement('script'); 
    script.type = 'text/javascript'; 
    script.src = url; 

    script.onload = function() { 
     app.scripts[url] = true; 
     callback(); 
    } 
    // Fire the loading 
    head.appendChild(script); 
    } 
}; 

を、私は、コンポーネントベースのシステムで働いています。この問題を説明するには、同じページに2つのGoogleマップコンポーネントがあるとします。どちらもコンポーネントのインスタンスです。そのような彼らのコンストラクタでは、私は

constructor(selector) { 

    super(selector); 

    // API load status 
    this._api = false; 
    // load the maps API 
    app.utilities.loadScript('https://maps.googleapis.com/maps/api/js?v=3.exp&key=' + app.config.mapsKey, this.initMap.bind(this)); 

    } 

は、私は、コンポーネントの2つのインスタンスが同じスクリプトをロードする場合、それは二回ロードされるべきではないという事態を予想...、メソッドを呼んでいます。そのため、loadScriptヘルパーの内部で、すでにロードされているスクリプトのグローバル配列を保持しています。app.scripts [url] = true;

しかし、複数のloadScript呼び出しが相互に非常に近く開始されるため、この方法は機能しません。最初のものはまだ完了していないので(進行中)、2番目の呼び出しが別の呼び出しを開始します。

私はすぐにグローバル配列内のスクリプトに "ローディング"ステータスを設定することを検討していますが、そのようなトリガーが必要なので、2番目の呼び出しがどのように最初のものを聞くことができるか不思議ですさもなければ、コールバックがあまりにも早く発生します。

私はおそらくこれを思っている気がしますか?編集

:少し微調整して、@siamによって回答に基づいてこれを解決したコードを含むは、追加:メソッドは今loadScriptEventということ

app.utilities.loadScriptEvent = function loadScript(url, eventName) 
{ 

    if (app.scripts[url] == 'loading') { 
     return true; 
    } 

    else { 
    app.scripts[url] = 'loading'; 

    var event = new CustomEvent(eventName); 

    // Adding the script tag to the head as suggested before 
    var head = document.getElementsByTagName('head')[0]; 
    var script = document.createElement('script'); 
    script.type = 'text/javascript'; 
    script.src = url; 

    // Then bind the event to the callback function. 
    // There are several events for cross browser compatibility. 
    //script.onreadystatechange = callback; 

    script.onload = function() { 
     app.scripts[url] = true; 
     app.window.dispatchEvent(event); 
    } 
    // Fire the loading 
    head.appendChild(script); 
    } 
}; 

注意、および第二パラメータことコールバックではなくイベント名です。 2つのコンポーネントがほぼ同時にこの呼び出しを行うことができたとしても、両方とも同じ単一のイベントを聴いているという考えがあります。これでは十分ではありません。最初のスクリプトが既にスクリプトの読み込みに忙しい場合は、2番目の要求を停止する必要があります。私はロード状態でそれを実現しました。このメソッドを次のように呼び出します。

app.utilities.loadScriptEvent('https://maps.googleapis.com/maps/api/js?v=3.exp&key=' + app.config.mapsKey, "gmloaded"); 
app.window.addEventListener('gmloaded',this.initMap.bind(this)); 

これはうまく動作します。コンポーネントインスタンスは互いの知識を持っていませんが、スクリプトはまだ非同期に一度だけロードされます。一度コードを実行するとすぐに実行できます。

+0

使用 'setInterval'最初の要求が完了したかどうかをチェックするのと、それは、第2の1を開始している場合と、その区間をクリアする – m87

+0

@サイアム。私はそのような答えを恐れていたが、唯一の方法かもしれない。ただし、2つ目の要求は最初の要求を認識していません(2つのコンポーネントインスタンスが互いを認識しないため)。 – Ferdy

+1

um ...多分別の方法があります。最初の要求が完了したときにトリガーされるカスタムイベントを作成できます。そのイベントで最初のリクエストの 'data'を渡すこともできます。 – m87

答えて

1

次のコードは、あなたにそれを行うことができる方法についての大まかな与えるかもしれない:

// using jQuery 

app.utilities.loadScript = function loadScript(url, callback) { 
    ... 
    script.onload = function(data) { 
     app.scripts[url] = true; 
     callback(); 
     ... 
     $(document).trigger('firstRqstCompleted', data); 
    } 
    ... 
} 

$(document).on('firstRqstCompleted', function(e, data) { 
    // do stuff with first request's data 
    // initiate second request 
}); 
+0

コードをありがとうございますが、残念ながらこの解決策では問題は解決しません。問題の性質は、loadscriptへの両方の呼び出しがお互いに非常に速くなることです。したがって、あなたがonloadに入れたコードは、同じことをすることによる2番目の要求を止めることはありません。カスタムイベントハンドラでこれを試しただけで、2回呼び出されます。 – Ferdy

+0

オンロードが2回トリガされるのを避けるために、コードを少し微調整する必要がありました(私の編集した回答を参照)。しかし、イベントを使用するという一般的な考え方が正しいので、正しい答えとしてマークしました。 – Ferdy

+0

ありがとう!それはうれしかったです。 :) – m87

関連する問題