延迟jquery承诺

时间:2015-06-10 04:13:13

标签: jquery promise jquery-deferred

我无法找到delay承诺的waitjQuery函数。我在SO上找到了一个函数(Using jQuery.Deferred to avoid nested setTimeout callbacks):

function delay(time) {
    return function () {
        console.log("Delaying");
        var ret = new $.Deferred();
        setTimeout(function () {
            ret.resolve();
        }, time);
        return ret;
    };
}

而且,这就是我使用它的方式:

 run: function () {
        return $()
            .promise()
            .then(function () {
                console.log("call together");
                console.log("call together");    
            })
            .then(delay(2000))
            .then(function () {
                console.log("call first");
            })
            .then(delay(2000))
            .then(function () {
                console.log("call second");
            })
    }

我想扩展我可以编写的promise或deferred对象:

run: function () {
            return $()
                .promise()
                .then(function () {
                    console.log("call together");
                    console.log("call together");    
                })
                .delay(2000)
                .then(function () {
                    console.log("call first");
                })
                .delay(2000)
                .then(function () {
                    console.log("call second");
                })
        }

3 个答案:

答案 0 :(得分:4)

正如@Bergi所说,jQuery Deferreds / Promises不能通过原型继承扩展。

相反,jQuery采用的模型是允许使用语法扩展单个Promise实例:

~ bosh -v                                           
BOSH 1.2981.0

通过使用一堆方法定义构造函数,可以使用简单的语法扩展任何jQuery Deferred或Promise

deferred.promise(target);
//or, 
promise.promise(target); //(though the documentation doesn't make this clear)
// where `target` is an "object onto which the promise methods have to be attached"
// see https://api.jquery.com/deferred.promise/

在我未发表的,未记录的jQuery promises Playground中,构造函数名为.promise(Constructor()) 并保存在jQuery名称空间中,因此我使用的实际语法是:

$P

您需要注意的是,在大多数情况下,没有必要明确调用.promise($.$P()) ,因为Playground包含一个返回已经扩展的Promise的$.$P()方法。

这是Playground的缩写版本,足以提供$.when_()方法:

.delay()

完整的Playground还包含一大堆用于其他目的的静态和promise实例方法,开发它们是该剧的精髓。

使用Playgound的基本规则如下:

  • 所有Playground的静态和承诺方法都以" _"下划线。
  • 只需安装Playgound即可使用静态方法,例如(function($) { /* *********************************** * The $.$P function returns an object * designed to be extended with * promise methods using the syntax : * myDeferred.promise($.$P()) * myPromise.promise($.$P()) * where `myDeferred`/`myPromise` * are jQuery Deferred/Promise objects. * ***********************************/ /* *********************************** * Methods * ***********************************/ $.$P = function() { if (this instanceof $.$P) { return this; } else { return new $.$P(); } }; $.$P.prototype.then_ = function(fa, fb) { /* A promise method that is the same as .then() * but makes these extra methods available * down-chain. */ return this.then(fa||null, fb||null).promise($.$P()); } $.$P.prototype.delay_ = function(ms) { /* A promise method that * introduces a down-chain delay. */ var promise = this; function f(method) { return function() { setTimeout(function(){ method.apply(null,this); }.bind(arguments), ms||0); }; } return $.Deferred(function(dfrd) { promise.then(f(dfrd.resolve), f(dfrd.reject)); }).promise($.$P()); } /* *********************************** * Utility functions * ***********************************/ function consolidate(args) { /* Convert mixed promises/arrays_of_promises to single array. * Called by all the when_() methods below. */ return Array.prototype.slice.apply(args).reduce(function(arr, current) { return arr.concat(current); }, []); } /* *********************************** * This section extends the jQuery namespace * with a "jQuery.when_()" method. * *********************************** */ $.extend({ 'when_': function() { return $.when.apply(null, consolidate(arguments)).promise($.$P()).then_(function() { return consolidate(arguments); }); }, }); })(jQuery);
  • 通过包含静态方法(例如$.when_()或链接.when_())来扩展承诺链中的承诺。
  • 在承诺链中,使用" ... _"扩展程序仍然可用(链中)方法而不是标准方法,例如.promise($.$P())代替.then_()

以下是如何使用它来强加问题所需的延迟:

.then()

<强> DEMO

在演示中,按钮的点击处理程序进一步显示了如何使用Playground。

使用游乐场的Provisos:

  • 正如我所说 - 它是一个游乐场
  • 作为jQuery的适配器,而不是补丁,它在某些地方效率非常低。最糟糕的是,除了返回的方法之外,某些方法还会产生中间承诺。
  • 未按照生产代码中使用的标准进行测试,因此请谨慎使用。

最后,如果你决定用jQuery实现延迟,只考虑上面的内容。使用已经有jQuery(function($) { var MYNAMESPACE = { run: function (t) { return $.when_() .then_(function () { log("call together"); log("call together"); }) .delay_(t) .then_(function () { log("call first"); }) .delay_(t) .then_(function () { log("call second"); }); } } }); 方法的promise lib远比这简单得多。

答案 1 :(得分:0)

修改,更新

尝试将属性delay添加到jQuery.Deferred

    delay: function(t) {
      return this.then(function() {
        var args = arguments;
        return new $.Deferred(function(d) {
          setTimeout(function() {
            // return `data`, if any, to next method, e.g., `.then`, in chain
            d.resolveWith(this, args)
          }.bind(this), t || 0)
        }).promise()
      })
    }

(function($) {
  $.Deferred = function(a) {
    var b = [
        ["resolve", "done", $.Callbacks("once memory"), "resolved"],
        ["reject", "fail", $.Callbacks("once memory"), "rejected"],
        ["notify", "progress", $.Callbacks("memory")]
      ],
      c = "pending",
      d = {
        delay: function(t) {
          return this.then(function() {
            var args = arguments;
            return new $.Deferred(function(d) {
              setTimeout(function() {
                // return `data`, if any, to next method, e.g., `.then`, in chain
                d.resolveWith(this, args)
              }.bind(this), t || 0)
            }).promise()
          })
        },
        state: function() {
          return c
        },
        always: function() {
          return e.done(arguments).fail(arguments), this
        },
        then: function() {
          var a = arguments;
          return $.Deferred(function(c) {
            $.each(b, function(b, f) {
              var g = $.isFunction(a[b]) && a[b];
              e[f[1]](function() {
                var a = g && g.apply(this, arguments);
                a && $.isFunction(a.promise) 
                ? a.promise()
                  .done(c.resolve)
                  .fail(c.reject)
                  .progress(c.notify) 
                : c[f[0] + "With"](this === d 
                  ? c.promise() 
                  : this, g ? [a] : arguments)
              })
            }), a = null
          }).promise()
        },
        promise: function(a) {
          return null != a ? $.extend(a, d) : d
        }
      },
      e = {};
    return d.pipe = d.then, $.each(b, function(a, f) {
      var g = f[2],
        h = f[3];
      d[f[1]] = g.add, h && g.add(function() {
        c = h
      }, b[1 ^ a][2].disable, b[2][2].lock), e[f[0]] = function() {
        return e[f[0] + "With"](this === e ? d : this, arguments), this
      }, e[f[0] + "With"] = g.fireWith
    }), d.promise(e), a && a.call(e, e), e
  }

}(jQuery));

var p = {
  run: function() {
    return $()
      .promise()
      .then(function() {
        console.log("call together");
        console.log("call together");
        // do stuff
        // pass `data` to next `.then`
        return "call first";
      })
      .delay(2000)
      .then(function(data) {
        console.log(data);
      })
      .delay(2000)
      .then(function() {
        console.log("call second");
      })
  }
};

p.run();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>

答案 2 :(得分:0)

这是我的解决方案。我打包$.Deferred(afterBuild)并换行原始afterBuild,然后换行.promise(obj)方法,使用自定义obj方法扩展给定delay。哪个使用window.setTimeout

注意:它只会延迟done分支。

&#13;
&#13;
function extendPromises(extensions) {
    $.Deferred = (function (originalDeferred) {
        return function (afterBuild) {
            var newAfterBuild = function (d) {
                d.promise = (function (originalPromise) {
                    return function (obj) {
                        return originalPromise.call(this, $.extend(obj, extensions));
                    };
                })(d.promise);
                if (afterBuild) afterBuild.apply(this, arguments);
                return this;
            };
            return originalDeferred.call(this, newAfterBuild);
        };
    })($.Deferred);
}

extendPromises({
    delay: function (delay) {
        return this.then(function (value) {
            var d = $.Deferred();
            window.setTimeout(function () {
                d.resolve(value);
            }, delay);
            return d.promise();
        });
    }
});

// so now I can do:
$.when("hello")
.then(function (value) { $("#log").append(value+"\n"); return value; })
.delay(1000)
.then(function (value) { $("#log").append(value); return value; });
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="log" rows=5></textarea>
&#13;
&#13;
&#13;