延迟 jquery 个承诺
delay for jquery promises
我找不到 delay
或 wait
函数用于 jQuery
承诺。我在 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");
})
}
编辑、更新
尝试将 属性 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>
正如@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 promises Playground 中,构造函数被命名为 $P
并保存在 jQuery 命名空间中,因此我使用的实际语法是:
.promise($.$P())
您需要注意,在大多数情况下,没有必要显式调用 $.$P()
,因为 Playground 包含一个 $.when_()
方法,该方法 return 已经扩展承诺。
这是 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 还包括一大堆用于其他目的的更多静态和 promise 实例方法,开发它们是游戏的精髓。
使用 Playgound 的基本规则如下:
- Playground 的所有 static 和 promise 方法都以“_”下划线结尾。
- 只需安装 Playgound 即可使用静态方法,例如
$.when_()
。
- 承诺链中的承诺通过包含静态方法扩展,例如
.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");
});
}
}
});
在演示中,按钮的点击处理程序进一步说明了如何使用 Playground。
关于使用 Playground 的附带条件:
- 正如我所说 - 这是一个 游乐场。
- 作为 jQuery 的适配器,而不是补丁,它在某些地方效率极低。最糟糕的方面是,一些方法除了 return.
之外还创建了一个中间承诺
- 未按照生产代码中使用所需的标准进行测试,因此请谨慎使用。
最后,如果您决定使用 jQuery 实现延迟,请仅考虑以上内容。使用已经具有 .delay()
方法的承诺库要简单得多。
这是我的解决方案。我包装 $.Deferred(afterBuild)
并包装原始 afterBuild
,然后包装 .promise(obj)
方法,使用自定义 delay
方法扩展给定的 obj
。其中使用 window.setTimeout
:
注意:它只会延迟 done
分支。
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; });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="log" rows=5></textarea>
我找不到 delay
或 wait
函数用于 jQuery
承诺。我在 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");
})
}
编辑、更新
尝试将 属性 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>
正如@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 promises Playground 中,构造函数被命名为 $P
并保存在 jQuery 命名空间中,因此我使用的实际语法是:
.promise($.$P())
您需要注意,在大多数情况下,没有必要显式调用 $.$P()
,因为 Playground 包含一个 $.when_()
方法,该方法 return 已经扩展承诺。
这是 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 还包括一大堆用于其他目的的更多静态和 promise 实例方法,开发它们是游戏的精髓。
使用 Playgound 的基本规则如下:
- Playground 的所有 static 和 promise 方法都以“_”下划线结尾。
- 只需安装 Playgound 即可使用静态方法,例如
$.when_()
。 - 承诺链中的承诺通过包含静态方法扩展,例如
.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");
});
}
}
});
在演示中,按钮的点击处理程序进一步说明了如何使用 Playground。
关于使用 Playground 的附带条件:
- 正如我所说 - 这是一个 游乐场。
- 作为 jQuery 的适配器,而不是补丁,它在某些地方效率极低。最糟糕的方面是,一些方法除了 return. 之外还创建了一个中间承诺
- 未按照生产代码中使用所需的标准进行测试,因此请谨慎使用。
最后,如果您决定使用 jQuery 实现延迟,请仅考虑以上内容。使用已经具有 .delay()
方法的承诺库要简单得多。
这是我的解决方案。我包装 $.Deferred(afterBuild)
并包装原始 afterBuild
,然后包装 .promise(obj)
方法,使用自定义 delay
方法扩展给定的 obj
。其中使用 window.setTimeout
:
注意:它只会延迟 done
分支。
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; });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="log" rows=5></textarea>