私は、getScriptをかなり広範囲に使用する必要があるエンジンを書いています。使いやすくするために、独自の関数にプッシュしましたが、関数自体が同期していることを確認する必要があります。残念ながら、先に進む前に、ロードするスクリプトが実際にロードを完了するまでgetScriptを待機させることができないようです。呼び出しを行う前に、jQueryのajax asynchプロパティをfalseに設定してみました。 jQueryのwhen/doneプロトコルを使用することを考えていますが、関数内に配置して関数自体を同期させるロジックに頭を悩ませているようには見えません。どんな助けでも大歓迎です!
function loadScript(script){
//Unrelated stuff here!!!
$.when(
$.getScript(script,function(){
//Unrelated stuff here!!!
})).done(function(){
//Wait until done, then finish function
});
}
ループコード(リクエストによる):
for (var i in divlist){
switch($("#"+divlist[i]).css({"background-color"})){
case #FFF:
loadScript(scriptlist[0],divlist[i]);
break;
case #000:
loadScript(scriptlist[2],divlist[i]);
break;
case #333:
loadScript(scriptlist[3],divlist[i]);
break;
case #777:
loadScript(scriptlist[4],divlist[i]);
break;
}
}
すでに述べたように、Ajax呼び出しをpromiseオブジェクトにチェーンするのは比較的簡単です。 なぜスクリプトが次々にロードされなければならないかわかりませんが、それには理由があります。
ただし、同じ関数を異なる引数で呼び出すだけの場合は、switch
ステートメントを削除します。例えば。すべてのスクリプトURLをマップに配置できます。
var scripts = {
'#FFF': '...',
'#000': '...'
// etc.
};
.then
に渡されるコールバックから別のpromiseを返すだけで、promiseをチェーンできます[ドキュメント] 。あなたがする必要があるのは、promiseまたは据え置きオブジェクトから始めることです:
var deferred = new $.Deferred();
var promise = deferred.promise();
for (var i in divlist) {
// we need an immediately invoked function expression to capture
// the current value of the iteration
(function($element) {
// chaining the promises,
// by assigning the new promise to the variable
// and returning a promise from the callback
promise = promise.then(function() {
return loadScript(
scripts[$element.css("background-color")],
$element
);
});
}($('#' + divlist[i])));
}
promise.done(function() {
// optional: Do something after all scripts have been loaded
});
// Resolve the deferred object and trigger the callbacks
deferred.resolve();
loadScript
では、$.getScript
から返されたpromiseまたは.done
から返されたpromiseを返すだけです。
function loadScript(script_url, $element){
// Unrelated stuff here!!!
return $.getScript(script_url).done(function(){
// Unrelated stuff here
// do something with $element after the script loaded.
});
}
スクリプトはすべて、ループ内のアクセス順に呼び出されます。 divlist
が配列の場合、for...in
ループの代わりに通常のfor
ループを実際に使用する必要があることに注意してください。
これは私にとってはうまくいき、あなたを助けるかもしれません。
$.ajax({
async: false,
url: "jui/js/jquery-ui-1.8.20.min.js",
dataType: "script"
});
基本的に、私は省略表記をバイパスしてasync: false
に追加しました
知っていますか $.getScript
accepts スクリプトが読み込まれた後に同期的に呼び出されるコールバック関数?
例:
$.getScript(url,function(){
//do after loading script
});
さらに2つの解決策があります。a pure js one and one for multiple js load です。
この方法を試して、遅延オブジェクトで配列を作成し、「適用」で$ .whenを使用します
var scripts = [
'src/script1.js',
'src/script2.js'
];
var queue = scripts.map(function(script) {
return $.getScript(script);
});
$.when.apply(null, queue).done(function() {
// Wait until done, then finish function
});
var getScript = function(url) {
var s = document.createElement('script');
s.async = true;
s.src = url;
var to = document.getElementsByTagName('script')[0];
to.parentNode.insertBefore(s, to);
};
@Felix Klingの回答は素晴らしいスタートでした。ただし、.done()
で返された結果の最後にある.getScripts()
の全体に少し問題があることがわかりました。ループ内からの連鎖.getScript()
反復の最後のプロミスが必要です。これが彼のソリューションの修正バージョンです(ありがとう、BTW)。
(function ($) {
var fetched = new function () {
this.scripts = [];
this.set = [];
this.exists = function (url) {
var exists = false;
$.each(this.set, function (index, value) {
if ((url || '') === value) {
exists = true;
return false;
}
});
return exists;
};
this.buildScriptList = function () {
var that = this;
that.set = [];
$('script').each(function () {
var src = $(this).attr('src') || false;
if (src) {
that.set.Push(src);
}
});
$.merge(this.set, this.scripts);
return this;
};
},
getScript = $.getScript;
$.getScript = function () {
var url = arguments[0] || '';
if (fetched.buildScriptList().exists(url)) {
return $.Deferred().resolve();
}
return getScript
.apply($, arguments)
.done(function () {
fetched.scripts.Push(url);
});
};
$.extend({
getScripts: function (urls, cache) {
if (typeof urls === 'undefined') {
throw new Error('Invalid URL(s) given.');
}
var deferred = $.Deferred(),
promise = deferred.promise(),
last = $.Deferred().resolve();
if (!$.isArray(urls)) {
urls = [urls];
}
$.each(urls, function (index) {
promise = promise.then(function () {
last = $.getScript(urls[index]);
return last;
});
});
if (Boolean(cache || false) && !Boolean($.ajaxSetup().cache || false)) {
$.ajaxSetup({cache: true});
promise.done(function () {
$.ajaxSetup({cache: false});
});
}
deferred.resolve();
return last;
}
});
})($);
フェッチした関数を無視して(潜在的な冗長呼び出しを減らすために実装しました-これが.getScript()
を乗っ取った理由です)、変数last
が.getScripts()
メソッド内で設定されている場所を確認できます。デフォルトでは解決された遅延オブジェクトなので、urls配列が空の場合、返された結果に渡されて、外側の.done()
呼び出しがアタッチされます。それ以外の場合は、必然的にチェーンされた.getScript()
呼び出しからの最後のpromiseオブジェクトが割り当てられるため、すべてが関数の外部から同期されたままになります。
最初に作成された据え置きオブジェクトを呼び出し元に戻す前に解決した場合、オブジェクトを戻しても機能しません(これは jQueryの公式ドキュメント に従って行うことになっています)。
function loadStuff(data) {
var version = {
'accounting': '1.2.3',
'vue': '1.2.3',
'vueChart': '1.2.3'
};
$.getScripts([
'https://cdnjs.cloudflare.com/ajax/libs/accounting.js/' + version.accounting + '/accounting.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/vue/' + version.vue + '/vue.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/vue-chartjs/' + version.vueChart + '/vue-chartjs.min.js'
], true)
.done(function () {
// do stuff
})
.fail(function () {
throw new Error('There was a problem loading dependencies.');
});
}