正如 @Bergi 所说,jQuery Deferreds/Promises 不能通过原型继承进行扩展。
相反,jQuery 采用的模型是允许使用以下语法扩展单个 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 Deferred 或 Promise 都可以使用简单的语法进行扩展
.promise(Constructor())
在我未发布、未记录的 jQuery Promise Playground 中,构造函数被命名为$P
并保存在 jQuery 命名空间中,因此我使用的实际语法是:
.promise($.$P())
您需要注意的是,在大多数情况下,没有必要调用$.$P()
明确地,因为 Playground 包括$.when_()
返回已扩展 Promise 的方法。
这是 Playground 的缩写版本,足以提供.delay()
方法 :
(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);
完整的 Playground 还包括一大堆用于其他目的的静态方法和承诺实例方法,开发它们是游戏的本质。
使用游乐场的基本规则如下:
- 所有 Playground 的静态方法和 Promise 方法都以下划线“_”结尾。
- 静态方法,例如
$.when_()
,只需安装 Playground 即可使用。
- 承诺链中的承诺通过包含静态方法来扩展,例如
.when_()
,或链接.promise($.$P())
.
- 在承诺链中,通过使用“..._”方法而不是标准方法,扩展保持可用(沿着链),例如
.then_()
代替.then()
.
因此,以下是如何使用它来施加问题所需的延迟:
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");
});
}
}
});
DEMO http://jsfiddle.net/r6hrtv1q/
在演示中,按钮的单击处理程序进一步指示了如何使用 Playground。
使用游乐场的限制条件:
- 正如我所说 - 这是一个操场.
- 作为 jQuery 的适配器,而不是补丁,它在某些地方效率非常低。最糟糕的方面是,某些方法除了返回的承诺之外还创建了中间承诺。
- 未按照生产代码中使用所需的标准进行测试,因此请谨慎使用。
最后,如果您决定使用 jQuery 实现延迟,则仅考虑上述内容。使用已经有的承诺库要简单得多.delay()
method.