【问题标题】:jQuery deferred object called twicejQuery延迟对象调用了两次
【发布时间】:2013-12-06 11:07:26
【问题描述】:

我在 jQuery 1.7 中遇到了 Deferred 对象的以下问题。这是我的问题的简化版本。跟着小提琴 -

http://jsfiddle.net/daljit/3gbrD/1/embedded/result/

下面是代码sn-p。

var resolveDeferred = false;
var objDeferred = $.Deferred();

function changeDeferred() {
    objDeferred.done(myDoneMethod);
    if (resolveDeferred) {
        objDeferred.resolve();
    }
    resolveDeferred = true;
}

function myDoneMethod() {
    console.log("I am called");
}
<input type="button" value="clickMe" onclick ="changeDeferred()" />

我们可以看到在“clickme”按钮上单击两次,显示两个警报。

有什么办法可以解决这个问题,所以当deferred object被解析时,它只调用了一次,因为方法名是一样的。

对不起,我没有正确解释问题,代码只是为了演示问题。因为方法名称相同所以它不应该调用它两次,或者问问题的方式是 - 是否有任何方法可以检查延迟对象的队列,所以我可以看到有多少方法附加到延迟对象以及方法是否已经附加,所以不要再次附加它。 抱歉没有说清楚。

【问题讨论】:

    标签: jquery jquery-deferred


    【解决方案1】:

    这可以满足您的需求,使用您自己的队列来检查任何重复的回调:

    DEMO

    var objDeferred = $.extend({}, $.Deferred(), {
        queue: [],
        done: function () {
            var callback = arguments[0];
            if (!~$.inArray(callback.toString(), this.queue)) {  
                this.queue.push(callback.toString());
                this.then($.proxy(function(){this.queue = [];callback()},this));
            }         
            return this
        }
    });
    

    【讨论】:

      【解决方案2】:

      在第一次单击changeDeferred 函数时,将resolveDeferred 设置为true,并将myDoneMethod 添加到objDeferred。 在第二次单击时,您再次将myDoneMethod 添加到objDeferred 并解决它。 解析后所有done调用,你添加两个回调 - 两个调用。

      【讨论】:

      • 感谢cmets,我了解代码,代码只是为了演示问题。因为方法名相同所以不应该调用两次,或者是否有任何方法可以检查延迟对象的队列,所以我可以查看该方法是否已经附加,所以不要再次附加它。谢谢,
      • no method 检查完成的回调堆栈。最好在向 Defered 对象添加内容之前执行此操作。
      • 您应该使用api.jquery.com/deferred.state 代替resolvedDeferred 变量,正如这里摆弄的jsfiddle.net/3gbrD/5
      【解决方案3】:

      这是一个基于 A Wolff 答案的版本,但使用了新方法 .doneUnique(),而 .done() 可用于非唯一用途。

      function myDeferred() {
          return $.extend({}, $.Deferred(), {
              dummyQueue: $.Callbacks(),
              doneUnique: function () {
                  var that = this;
                  $.each(arguments, function(i, fn) {
                      if($.isArray(fn)) {
                          that.done(fn);//add arrays of callbacks unconditionally 
                      }
                      else if (!that.dummyQueue.has(fn)) {//test - already added?
                          that.done(fn);
                          that.dummyQueue.add(fn);//remember fn, so it's not added again
                      }
                  });
                  return this;//for method chaining
              }
          });
      }
      

      DEMO

      注意事项:

      • 一个虚拟的$.Callbacks() 队列用于记住唯一的回调而不是一个普通的数组,允许使用.has(),这可以说比$.inArray() 更方便。
      • 成功通过唯一性陷阱的 Callbaks 最终会进入标准 .done() 队列。
      • .doneUnique() 模仿 .done(),因为它将处理多个参数(单个调用中的多个回调)。
      • 为传递回调数组做了规定。此类数组是无条件添加的(即不对数组包装的回调进行唯一性检查)。这提供了强制.doneUnique() 表现得像.done() 的选项。

      【讨论】:

        猜你喜欢
        • 2019-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-31
        • 2011-12-17
        • 1970-01-01
        相关资源
        最近更新 更多