实现某些异步函数超时是一种常见模式,使用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();
}
现在我们可以执行一些名为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' );
}
);
好了,让我们在这个故事中来个转折吧!假设myFunc
本身返回一个promise (注意: promise没有延迟,我不能更改它):
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();
}
现在,如果我将myFunc
包装在timeout
中,我将失去处理不同于超时的错误的能力。如果myFunc
发出进度事件,我也会丢失它。
所以问题是:如何修改timeout
函数,以便它可以接受返回承诺的函数,而不会丢失它们的错误/进度信息?
发布于 2014-06-12 20:04:15
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();
}
发布于 2016-09-28 22:38:54
我知道这是两年前的事了,但如果有人在寻找答案……
我认为本杰明说得差不多,因为你想让你的超时单独处理,所以我们先从他的延迟功能开始。
function delay(ms){
var d = $.Deferred();
setTimeout(function(){ d.resolve(); }, ms);
return d.promise();
}
然后,如果你想在代码执行之前等待,你可以调用你想要因为这个承诺而延迟的方法。
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));
});
}
这通常是我在寻找复习课程时要做的事情(我来这里的原因)。然而,问题不在于延迟执行,而是在执行时间太长时抛出错误。在这种情况下,这会使事情变得复杂,因为您不想在没有必要的情况下等待超时,所以您不能只将这两个承诺包装在“何时”中。看起来我们还需要再推迟一次。(参见Wait for the first of multiple jQuery Deferreds to be resolved?)
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;
});
}
我们可以简化这一过程,因为我们知道在这种情况下,主延迟只会在超时首先发生的情况下才会拒绝,并且只有在functPromise首先解决时才会解决。正因为如此,我们不需要将functPromise传递给主延迟解析,因为它是唯一可以传递的东西,并且我们仍然在作用域中。
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;
});
}
https://stackoverflow.com/questions/24183480
复制相似问题