jQuery中如何取消一个延迟承诺(Deferred Promise)

11

如何取消一个Promise而不从DOM中删除元素?

示例代码

我运行了这段代码:

$("#box")
  .delay(2000)
  .show("slow")
  .delay(2000)
  .promise()                            
  .then(function(){log("Done");});

在此之后,是否有一种方法可以取消Promise?clearQueue()stop(true)都无法工作,因为我尝试取消的不是动画。我看到应该使用remove(),但我只想停止Promise,而不是删除整个元素。


1
如果您仅拥有Promise对象(而没有访问原始Deferred的权限),那么应该不可能这样做。 Promise的想法是能够监听Deferred被解决或拒绝,而没有解决/拒绝功能。 您可以创建一个Promise包装器,它公开了原始Promise函数,但所有回调都绑定了一个包装函数,该函数侦听某种标志以避免在Deferred标记为取消时触发回调。 - Germán Enríquez
几乎,实际上你只想创建一个延迟并手动拒绝或解决它,以你认为合适的方式。 - Patrick Lee Scott
4个回答

4

好消息,从昨天开始你可以取消你的承诺。

我发布了我的小插件jquery-timing的新版本,其中包含许多方法之一是称为.wait()和.unwait()。

var deferred = $("#box").delay(2000).show("slow").delay(2000).promise();
$.wait(deferred, function(){ log("Done"); });

如果您想注销回调函数:
$.unwait();

这些静态版本的wait和unwait还支持可选的组名,以不取消任何处理程序,仅针对特定集合。此外,您还可以执行许多更智能的操作,例如:
$('#box').wait(deferred).addClass('ready');

或者将整个代码作为一个连续的链,不使用unwait选项:

$("#box").delay(2000).show("slow")
  .delay(2000).join(function(){log("Done");})).addClass('ready');

或者使用选项取消这两个暂停,甚至可以更短。
$("#box").wait(2000).show("slow",$)
  .wait(2000, function(){log("Done");})).addClass('ready');

只需查看文档、示例和API,找到最适合您的。


1
只是一个问题:我不能使用deferred.reject()吗? - Pulak Kanti Bhattacharyya

2
我相信你可以使用 $('#box').remove(); 根据jQuery文档(http://api.jquery.com/promise/),返回的Promise与存储在元素的.data()上的Deferred对象相关联。由于.remove()方法不仅会删除元素本身,还会删除元素的数据,因此它将阻止任何未解决的Promise解决。如果需要在元素的Promise解决之前从DOM中删除元素,请改用.detach()方法,并在解决后跟随.removeData()方法。

我看到了remove(),但是我想知道是否有一种方法可以在不删除实际元素的情况下完成它。已编辑问题。 - ripper234
1
是的,从dom中删除元素似乎并不理想。这是我能让它工作的唯一方法。祝你在寻找更好的解决方案时好运。 - Paul

1

我不知道你是否需要像http://jsfiddle.net/2cq8M/这样的东西?我涉及到了两个Promise(一个只是为了处理动画集结束时的情况,另一个则根据需要解决或拒绝)。


当然,我最好奇的是如果你拒绝了承诺,动画应该发生什么? - JayC
语法有点笨拙...我希望能够取消一个 Promise ... 在当前的实现中可能没有办法。 - ripper234

1
你在这种情况下应该使用延迟对象而不是 Promise,但是你可以使用动画的 Promise 来解决延迟对象。

http://jsfiddle.net/LG9eZ/9/

var stopDone = true;

function log(msg) {
    $(".debug").append(new Date() + " - " + msg + "<br/>");
}

log("Starting");

var boxAnimation = new $.Deferred();
boxAnimation.done(function() {
    log("Done");
});
boxAnimation.fail(function() {
    log("Stopped");
});


$("#box").delay(2000).show("slow").delay(2000).promise().then(function() {
    boxAnimation.resolve(); // when all the animations are done, resolve the deferred.
}); 


if (stopDone)
{
    boxAnimation.reject();
}

作为一个附注,延迟对象只能被拒绝或解决一次。一旦它们被拒绝或解决,你就不能改变它们的状态。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接