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

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (24)

使用缓存/承诺来实现一些异步函数的超时是一种常见模式:

// 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本身返回一个承诺(注意:承诺不推迟,我不能改变它):

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();
}

现在,如果我换myFunctimeout,我会宽松处理不同的错误,然后超时的能力。如果myFunc发生进展事件,我也会放弃这一点。

所以问题是:如何修改timeout函数,以便它可以接受返回promise的函数,而不会丢失错误/进度信息?

提问于
用户回答回答于
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();
}
用户回答回答于

你应该总是尽可能在最低的水平上。我们从基础开始。

我将在这里使用jQuery的承诺,但是这应该通过像Bluebird这样的更强大的库来完成。让我们开始简单的创建我们的delayas:

function delay(ms){
    var d = $.Deferred();
    setTimeout(function(){ d.resolve(); }, ms);
    return d.promise();
}

注意延迟没有任何意外,我们所有的延迟功能都会导致延迟ms几毫秒。

现在,对于您的图书馆,我们希望创建一个doSomething适用于承诺的版本:

 superImportantLibrary.doSomethingAsync = function(){
     var d = $.Deferred();
     superImportantLibrary.doSomething(function(data){ d.resolve(data); });
     return d.promise();
 };

注意我们的延迟和doSomethingAsync功能都只做一件事。现在乐趣开始了。

function timeout(promise,ms){
    var timeout = delay(ms); // your timeout
    var d = $.Deferred();
    timeout.then(function(){ d.reject(new Error("Timed Out")); });
    promise.then(function(data){ d.resolve(data); });
    return d.promise();
}

timeout(superImportantLibrary.doSomethingAsync(),1000).then(function(data){
     // handle success of call
}, function(err){
     // handle timeout or API failure.
});

现在在蓝鸟,这整个代码将是:

superImportantLibrary.doSomethingAsync().timeout(1000).then(function(){
    // complete and did not time out.
});

扫码关注云+社区