我有一个基于 apache、php、js/jquery 的网络应用程序。加载文档时初始化应用程序的一个模块。该序列调用一个执行许多任务的 init() 函数,除其他外,它通过 ajax 获取两个 html 对话框并将它们插入到现有页面中。对这些对话框的引用保存为变量,因此我不必在整个脚本中指定 jquery 选择器,而是可以简单地使用这些变量。这工作正常,除了在尝试将处理程序绑定到获取的对话框内的元素时变量“未定义”的情况很少(偶尔......)。这很奇怪,因为除了绑定之外,对话框在整个应用程序中都是可用的。这表明 ajax 调用成功,但显然存在某种竞争条件,在绑定尝试之后。
根据我的理解,这不应该发生,因为绑定是在 when() 的 .done() 部分完成的,并且只能在对话框的 ajax 检索在 when() 内完成后执行。
显然我在这里遗漏了一些基本的东西。有人对我有提示吗?
以下引用了工作实现的代码摘录。它们可能作为某些部分在语法上看起来无效,但这只是由于删除了与此处无关的代码部分。未缩短的代码工作正常。
变量:
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(){
// ...
});
// ...
});
// ...
})
缩短的初始化函数:
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的回答,我设法显然消除了原来的问题。到目前为止,我无法检测到更多失败的绑定尝试。但是我不能完全遵循这个建议:在他的回答中,他建议删除初始化方法中的 switch 语句以支持直接分配。这当然要优雅得多,但这行不通。我的印象是我对 javascript 如何处理存储在变量中的引用和/或函数存在一些误解。
也许您、Bergi 或其他人可以对此做出一些解释:
这是上面修改后的初始化方法:
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.element 等,但都失败了。在函数之外,变量 Shorty.Tracking.Dialog.List 和 Shorty.Tracking.-Dialog.Click 保持为空。
我是 web 东西和 js/jquery 的绝对新手。但我当然很想了解更多关于这种处理引用的方式。