我有一个基于apache,php,js / jquery的web applciation。加载文档时,将初始化应用程序的一个模块。该序列调用执行许多任务的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保持为空。
我是网络内容ans js / jquery的绝对新手。但我当然很想知道这种处理参考文献的方法。
答案 0 :(得分:2)
这是有问题的代码:
var dfd=new $.Deferred();
$.each(['list','click'], function(){
...
dfd.resolve/fail();
});
您只创建一个Deferred,但多次解决它。因此,当第一个解决方案发生时,第二个Ajax就不会完成。
所以,改为使用两个Deferred,并通过jQuery.when()
组合它们。另外,我认为你不需要自己创建Deferreds。只需从pipe()
来电中获取这两个。
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(...);
});
好的,我需要解释一下switch-Statement。确实,dialogs
对象中的值将从[未初始化]变量中分配并保持该值(undefined
),当重新分配字段时,Shorty
值不会更改。 Javascript中没有“指针”。我认为只有在成员运算符中使用当前dialog
变量而不是switch语句才有用。要分配到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;
}
(最终使用来自How do I make the first letter of a string uppercase in JavaScript?的代码段)