如果jQuery.hide()在Deferred回调中被调用,Callback不会触发
Callback doesn't fire if jQuery.hide() is invoked in a Deferred callback
我正在jWizard的[一个分支]上工作,增加对允许事件处理程序返回Promise
对象的支持。
下面的代码按预期工作:
- 调用元素的"stephide"事件
- 如果事件没有被取消,隐藏元素。
- 当元素被隐藏时,调用它的
stephidden
事件。
(简化为这个问题;(见原文)
/** Invokes the `stephide` event for the current element and hides
* it if the event handler doesn't prevent it.
*
* @param $el {jQuery} Element that will be hidden.
*/
_leave: function ($el) {
var event = $.Event("stephide"),
dfd = $.Deferred(),
effect = { effect: "blind", direction: "left", duration: 250 };
$el.trigger(event);
if(event.isDefaultPrevented()) {
dfd.reject();
} else {
$el.hide(effect, function() {
$el.trigger("stephidden");
dfd.resolve();
});
}
return dfd.promise();
}
然而,当我修改代码以期望Promise
时,传递给$el.hide()
的回调不会触发。元素会被隐藏,但回调函数不会被调用。
_leave: function ($el) {
var event = $.Event("stephide"),
dfd = $.Deferred(),
effect = { effect: "blind", direction: "left", duration: 250 };
$el.trigger(event);
// event.returnValue is a Promise object; see below.
$.when(event.returnValue).then(
function() {
// $el.hide DOES run...
$el.hide(effect, function() {
// ... but this code never does!
console.log("stephidden");
$el.trigger("stephidden");
dfd.resolve();
});
},
dfd.reject
);
return dfd.promise();
}
/** Event handler for the stephide event.
*/
$("...").on("stephide", function(event) {
var dfd = $.Deferred();
// ...
event.returnValue = dfd.promise();
});
我做错了什么?
我发现以下可能的问题:
-
如果
hide.returnValue
是一个承诺,当你认为它是,它没有解决,那么这可能会导致一个问题(我们看不到代码)。 -
如果有东西打断了隐藏动画(例如在动画完成之前的
.stop()
),则不会调用.hide()
的回调。你可以通过使用.promise()
而不是回调来解决中断问题,因为即使动画停止,这也总是解决的。 -
如果对象在动画完成之前从DOM中移除(使用类似于jQuery的
.remove()
或.empty()
或.html()
的父对象),那么它将不会调用它的回调。
如果你打算返回一个承诺,它通常也是一个更简单的接口,总是返回一个承诺(在你的hide.returnValue
中)。如果没有什么需要等待的,那么就返回一个已经解决的promise。这使得调用代码更简单,因为他们可以假设这里有一个承诺,然后编写一组代码。你说得好像那只是有时候的承诺,编码起来很痛苦。
我建议简化你的承诺代码,你可以使用现有的承诺。
我认为你可以用这段简化的代码做任何你想做的事情:
_leave: function ($el) {
var event = $.Event("stephide"),
effect = { effect: "blind", direction: "left", duration: 250 };
$el.trigger(event);
return $.when(event.returnValue).then(function() {
return $el.hide(effect).promise().then(function() {
console.log('stephidden');
$el.trigger("stephidden");
});
});
}
如果hide.returnValue
总是一个promise,那么你不需要$.when()
,因为你可以直接在promise上调用.then()
。在它周围使用$.when()
,即使hide.returnValue
不是承诺,.then()
也会执行。
这也使用内置的.promise()
函数来隐藏动画,而不是回调,以提高可靠性和使用承诺的一致性。
如果event.returnValue
始终是一个promise对象,那么您可以使用以下缩写版本:
_leave: function ($el) {
var event = $.Event("stephide"),
effect = { effect: "blind", direction: "left", duration: 250 };
$el.trigger(event);
return event.returnValue.then(function() {
return $el.hide(effect).promise().then(function() {
console.log('stephidden');
$el.trigger("stephidden");
});
});
}
- 如何使jQuery插件函数可调用以供独立使用,而不在集合上操作
- D3在一个调用中绘制不同的SVG形状,没有可见性
- 如何从Java/scala调用js美化程序
- 如何调用这个匿名 JavaScript 函数
- 如何从模块链中调用函数.导出到节点中
- 我需要从php调用javascript或jquery
- Chrome开发工具(如何知道我在调用哪个javascript对象)
- 单击按钮后如何逐个调用分区,上一个分区将隐藏
- 另一个ajax调用中的Jquery ajax调用在for循环中没有按预期工作
- Twitter Bootstrap typeahead:使用“this”获取上下文/调用元素
- Rails完成了200 OK,但$.ajax()调用'错误'callback而不是'成功;
- node-phantom createPage()从不调用callback
- 如果jQuery.hide()在Deferred回调中被调用,Callback不会触发
- 在异步.直到(test, function, callback)测试函数没有被重复调用
- 显式调用javascript callback
- Opera不调用flash的ExternalInterface.callback()函数在js内部由flash调用的回调
- Cordova -plugin-device-motion插件不调用callback
- 谷歌.Load从不调用callback
- Jquery.post()中从未调用过Callback
- 异步.Filter在所有迭代器完成之前调用callback