mno*_*tka 18 javascript jquery promise deferred jquery-deferred
这是使用deffered/promise实现某些异步函数超时的常见模式:
// Create a Deferred and return its Promise
function timeout(funct, args, time) {
var dfd = new jQuery.Deferred();
// execute asynchronous code
funct.apply(null, args);
// When the asynchronous code is completed, resolve the Deferred:
dfd.resolve('success');
setTimeout(function() {
dfd.reject('sorry');
}, time);
return dfd.promise();
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以执行一些调用的异步函数myFunc并处理超时:
// Attach a done and fail handler for the asyncEvent
$.when( timeout(myFunc, [some_args], 1000) ).then(
function(status) {
alert( status + ', things are going well' );
},
function(status) {
alert( status + ', you fail this time' );
}
);
Run Code Online (Sandbox Code Playgroud)
好吧,让我们来讲一下这个故事吧!想象一下,它myFunc本身会返回一个承诺(注意:承诺不延期,我不能改变它):
function myFunc(){
var dfd = new jQuery.Deffered();
superImportantLibrary.doSomething(function(data)){
if(data.length < 5){
dfd.reject('too few data');
}
else{
dfd.resolve('success!');
}
}, {'error_callback': function(){
dfd.reject("there was something wrong but it wasn't timeout");}
}});
return dfd.promise();
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我换myFunc的timeout,我会宽松处理不同的错误,然后超时的能力.如果myFunc发出进度事件,我也会松开它.
所以问题是:如何修改timeout函数以便它可以接受函数返回promises而不会丢失它们的错误/进度信息?
function timeout(funct, args, time) {
var deferred = new jQuery.Deferred(),
promise = funct.apply(null, args);
if (promise) {
$.when(promise)
.done(deferred.resolve)
.fail(deferred.reject)
.progress(deferred.notify);
}
setTimeout(function() {
deferred.reject();
}, time);
return deferred.promise();
}
Run Code Online (Sandbox Code Playgroud)
我意识到这是 2 岁,但万一有人正在寻找答案......
我认为 Benjamin 很接近,你会希望你的超时被单独处理,所以我们将从他的延迟功能开始。
function delay(ms){
var d = $.Deferred();
setTimeout(function(){ d.resolve(); }, ms);
return d.promise();
}
Run Code Online (Sandbox Code Playgroud)
然后,如果您想在代码执行之前等待,您可以调用您希望由于此承诺而延迟的方法。
function timeout(funct, args, time) {
return delay(time).then(function(){
// Execute asynchronous code and return its promise
// instead of the delay promise. Using "when" should
// ensure it will work for synchronous functions as well.
return $.when(funct.apply(null, args));
});
}
Run Code Online (Sandbox Code Playgroud)
这通常是我去寻找复习时想要做的(为什么我在这里)。然而,问题不是关于延迟执行,而是如果时间太长会抛出错误。在这种情况下,这会使事情变得复杂,因为如果您不需要,您不想等待超时,因此您不能将两个承诺包装在“何时”中。看起来我们需要另一个延迟混合。(请参阅等待多个 jQuery Deferreds 中的第一个被解决?)
function timeout(funct, args, time) {
var d = $.Deferred();
// Call the potentially async funct and hold onto its promise.
var functPromise = $.when(funct.apply(null, args));
// pass the result of the funct to the master defer
functPromise.always(function(){
d.resolve(functPromise)
});
// reject the master defer if the timeout completes before
// the functPromise resolves it one way or another
delay(time).then(function(){
d.reject('timeout');
});
// To make sure the functPromise gets used if it finishes
// first, use "then" to return the original functPromise.
return d.then(function(result){
return result;
});
}
Run Code Online (Sandbox Code Playgroud)
我们可以简化它,知道在这种情况下,主延迟仅在超时首先发生时拒绝,并且仅在 functPromise 首先解决时才解决。因此,我们不需要将 functPromise 传递给主 defer 解析,因为它是唯一可以传递的东西,而且我们仍在作用域内。
function timeout(funct, args, time) {
var d = $.Deferred();
// Call the potentially async funct and hold onto its promise.
var functPromise = $.when(funct.apply(null, args))
.always(d.resolve);
// reject the master defer if the timeout completes before
// the functPromise resolves it one way or another
delay(time).then(function(){
d.reject('timeout');
});
// To make sure the functPromise gets used if it finishes
// first, use "then" to return the original functPromise.
return d.then(function(){
return functPromise;
});
}
Run Code Online (Sandbox Code Playgroud)