首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在JavaScript中,如何在超时中包装承诺?

在JavaScript中,如何在超时中包装承诺?
EN

Stack Overflow用户
提问于 2014-06-12 19:42:58
回答 2查看 10.3K关注 0票数 20

实现某些异步函数超时是一种常见模式,使用deffered/promise:

代码语言:javascript
复制
// 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的异步函数并处理超时:

代码语言:javascript
复制
// 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没有延迟,我不能更改它):

代码语言:javascript
复制
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函数,以便它可以接受返回承诺的函数,而不会丢失它们的错误/进度信息?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-06-12 20:04:15

代码语言:javascript
复制
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();
}
票数 9
EN

Stack Overflow用户

发布于 2016-09-28 22:38:54

我知道这是两年前的事了,但如果有人在寻找答案……

我认为本杰明说得差不多,因为你想让你的超时单独处理,所以我们先从他的延迟功能开始。

代码语言:javascript
复制
function delay(ms){
    var d = $.Deferred();
    setTimeout(function(){ d.resolve(); }, ms);
    return d.promise();
}

然后,如果你想在代码执行之前等待,你可以调用你想要因为这个承诺而延迟的方法。

代码语言:javascript
复制
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?)

代码语言:javascript
复制
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传递给主延迟解析,因为它是唯一可以传递的东西,并且我们仍然在作用域中。

代码语言:javascript
复制
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;
    });
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24183480

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档