jQueryの競合状態/完了シーケンス?
-
13-12-2019 - |
質問
私はApache、PHP、JS / JQueryに基づくWebアプレーチを持っています。アプリケーションの1つのモジュールは、文書がロードされたときに初期化されます。そのシーケンスは、多くのタスクを実行するinit()関数を実行するinit()関数を実行します。なお、との中で、Ajaxを介して2つのHTMLダイアログをフェッチし、それらを既存のページに挿入します。これらのダイアログへの参照は変数として保存されるため、スクリプト全体でjQueryセレクタを指定する必要はありませんが、代わりにそれらの変数を使用するだけです。ハンドラをフェッチされたダイアログ内の要素にバインドしようとすると、変数が 'undefined'の場合は非常に少ない場合を除き、この機能が大丈夫です。これは奇数で、そのバインドとは別に、ダイアログはアプリケーション全体で使用可能です。これは、Ajax呼び出しが成功したことを示唆していますが、明らかにある種の競合状態があるため、変数はの後にバインド試行の後に設定されます。
私の理解の中では、when()の.done()部分で行われているため、これは起こるべきではありません()、AjaxのAjax検索がいつ終了したときにのみ実行されるべきです()。
気がかん、ここでは基本的なものがありません。誰もが私のためにヒントを受けましたか?
次に、作業実装からコード抜粋を引用しています。それらはいくつかの部分として構文的に無効に見えるかもしれませんが、それはここに関連しないコード部分の削除によるものです。 Unshorted Codeはうまく機能します。
変数:
Shorty.Tracking.Dialog.List:{};
Shorty.Tracking.Dialog.Click:{};
.
初期化シーケンス:
$(window).load(function(){
//...
var dfd = new $.Deferred();
$.when(
// load layout of dialog to show the list of tracked clicks
Shorty.Tracking.init()
).done(function(){
// bind actions to basic buttons
Shorty.Tracking.Dialog.List.find('#close').on('click',function(){
// ...
});
// ...
});
// ...
})
.
短縮init関数:
Shorty.Tracking.init:function(){
// ...
var dfd=new $.Deferred();
// two dialogs are used by this plugin
var dialogs={
'list': Shorty.Tracking.Dialog.List,
'click': Shorty.Tracking.Dialog.Click
};
// load dialogs from server
$.each(['list','click'],function(i,dialog){
if (...){
// ...
dfd.resolve();
}else{
// load dialog layout via ajax and create a freshly populated dialog
$.ajax({
type: 'GET',
url: OC.filePath('shorty-tracking','ajax','layout.php'),
data: { dialog: dialog},
cache: false,
dataType: 'json'
}).pipe(
function(response){return Shorty.Ajax.eval(response)},
function(response){return Shorty.Ajax.fail(response)}
).done(function(response){
// create a fresh dialog
// insert it alongside the existing dialogs in the top controls bar
$('#controls').append(response.layout);
switch (dialog){
case 'list':
Shorty.Tracking.Dialog.List=$('#controls #shorty-tracking-list-dialog').first();
break;
case 'click':
Shorty.Tracking.Dialog.Click=$('#controls #shorty-tracking-click-dialog').first();
} // switch
dfd.resolve();
}).fail(dfd.reject)
} // else
}); // each
return dfd.promise();
},
.
BERGIの答えが、明らかに元の問題を除去することができました。これまで私はもっと失敗したバインド試行を検出できませんでした。しかし、私は完全にその提案のようなものに従うことができませんでした。これは確かにはるかにエレガントですが、それはうまくいきません。私は、JavaScriptが参照や変数に格納されている関数を処理する方法についての私の側にいくつかのミサンダンスがあるという印象があります。
あなた、ベルギー、または他の誰かがこれで説明するいくつかの明るさを留めることができます:
上記からの変更の初期化方法です。
init:function(){
if (Shorty.Debug) Shorty.Debug.log("initializing tracking list");
// check if dialogs already exist
if ( $.isEmptyObject(Shorty.Tracking.Dialog.List)
&& $.isEmptyObject(Shorty.Tracking.Dialog.Click) ){
// two dialogs are used by this plugin
var dialogs={
'list': Shorty.Tracking.Dialog.List,
'click': Shorty.Tracking.Dialog.Click
};
// load dialogs from server
var dfds=$.map(dialogs,function(obj,dialog){
// load dialog layout via ajax and append it to the collection of dialogs in the controls
return $.ajax({
type: 'GET',
url: OC.filePath('shorty-tracking','ajax','layout.php'),
data: { dialog: dialog},
cache: false,
dataType: 'json'
}).pipe(
function(response){return Shorty.Ajax.eval(response)},
function(response){return Shorty.Ajax.fail(response)}
).done(function(response){
// create a fresh dialog and insert it alongside the existing dialogs in the top controls bar
$('#controls').append(response.layout);
// obj=$('#controls #shorty-tracking-'+dialog+'-dialog').first();
switch(dialog){
case 'list':
Shorty.Tracking.Dialog.List=$('#controls #shorty-tracking-list-dialog').first();
break;
case 'click':
Shorty.Tracking.Dialog.Click=$('#controls #shorty-tracking-click-dialog').first();
break;
} // switch
})
}) // map
return $.when.apply(null, dfds);
}else{
// dialogs already loaded, just clean them for usage
Shorty.Tracking.Dialog.List.find('#list-of-clicks tbody tr').remove();
new Deferred().resolve();
} // else
},
.
中央の割り当て文がコメントアウトし、現在以下のSwitchステートメントに置き換えられているのがわかります。 obj.lementなどのようないくつかのバリエーションを試しましたが、失敗しました。関数の外側のShorty.Tracking.Dialog.ListとShorty.Tracking.-Dialog.Clickは空です。
私はWebの絶対的なニュービー、JS / jQueryを掲載しています。しかし、私はこのような取扱いのためにこの方法についてもっと知ることが確かに興味があります。
解決
それは問題のあるコードです:
var dfd=new $.Deferred();
$.each(['list','click'], function(){
...
dfd.resolve/fail();
});
.
延期を1つだけ作成しますが、それを複数回解決します。そのため、最初の解像度が発生すると、2番目のAJAXは終了していません。
だから、代わりに2つの遅延を使用して、 jQuery.when()
を介してそれらを合わせます。また、あなたが遅延を自分で作成する必要があるとは思わない。 pipe()
呼び出しから取得する2つの2つを取ります。
function init() {
var dialogs={
'list': Shorty.Tracking.Dialog.List,
'click': Shorty.Tracking.Dialog.Click
};
var deferreds = $.map(dialogs, function(obj, dialog) {
return $.ajax(...).pipe(...).done(...
// really, don't use switch here:
obj.element = response.layout;
}); // done() returns the Deferred
});
return $.when.apply(null, deferreds);
}
...
$.ready(function($) {
init().done(...);
});
.
OK、スイッチステートメントについて説明する必要があります。これは、dialogs
オブジェクトの値が[未初期化]変数から割り当てられ、その値(undefined
)が再割り当てされたときにShorty
値が変更されません。 JavaScriptに「ポインタ」はありません。スイッチステートメントではなく、メンバー演算子で現在のdialog
変数を使用すると便利です。 Shorty.Tracking.Dialog.List
と.Click
に割り当てるには、
var dialogs = ["list", "click"];
var shortcut = Shorty.Tracking.Dialog; // some object
for (var i=0; i<dialogs.length; i++) {
// loop over them,
// do the ajax stuff
var element = $(repsonse.layout); // get the added element from the response
$('#controls').append(element);
shortcut[dialogs[i]] = element;
}
.