为 promise.all 中的每个 promise 设置超时 [英] Setting a timeout for each promise within a promise.all

查看:32
本文介绍了为 promise.all 中的每个 promise 设置超时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我能够成功执行 Promise.all,并优雅地处理解决和拒绝.但是,有些承诺在几毫秒内完成,有些可能/可能需要一段时间.

I am able to successfully perform a Promise.all, and gracefully handle resolves and rejects. However, some promises complete within a few milliseconds, some can/could take a while.

我希望能够为 Promise.all 中的每个 Promise 设置超时,这样它可以尝试最多花费 5 秒.

I want to be able to set a timeout for each promise within the Promise.all, so it can attempt to take a maximum of say 5seconds.

getData() {
    var that = this;
    var tableUrls = ['http://table-one.com','http://table-two.com'];
    var spoonUrls = ['http://spoon-one.com','http://spoon-two.com'];

    var tablePromises = that.createPromise(tableUrls);
    var spoonPromises = that.createPromise(spoonUrls);
    var responses = {};

    var getTableData = () => {
        var promise = new Promise((resolve, reject) => {
            Promise.all(tablePromises.map(that.rejectResolveHandle))
                .then((results) => {
                    responses.tables = results.filter(x => x.status === 'resolved');
                    resolve(responses);
                });
        });
        return promise;
    };

    var getSpoonData = () => {
        var promise = new Promise((resolve, reject) => {
            Promise.all(spoonPromises.map(that.rejectResolveHandle))
                .then((results) => {
                    responses.tables = results.filter(x => x.status === 'resolved');
                    resolve(responses);
                });
        });
        return promise;
    };


    return getTableData()
        .then(getSpoonData);
}

rejectResolveHandle() {
    return promise.then(function(v) {
        return {v:v, status: "resolved"};
    }, function(e) {
        return {e:e, status: "rejected"};
    });
}

createPromise(links) {
    var promises = [];
    angular.forEach(links, function (link) {
        var promise = that._$http({
            method: 'GET',
            url: link + '/my/end/point',
            responseType: 'json'
        });
        promises.push(promise);
    });

    return promises;
}

我已尝试向 createPromise() 添加超时,但这似乎不起作用.将超时设置为 300 毫秒,某些请求会持续 4 秒以上:

I have tried adding a timeout to createPromise(), however this does not seem to work. Setting a timeout to 300ms, some requests continue for 4+seconds:

createPromise(links) {
    var promises = [];
    angular.forEach(links, function (link) {
        var promise = that._$http({
            method: 'GET',
            url: link + '/my/end/point',
            responseType: 'json'
        });

        promise = new Promise((resolve) => {
            setTimeout(() => {
                resolve(promise);
            }, 300);
        });

        promises.push(promise);
    });

    return promises;
}

如果 Bluebird 能让事情变得更容易,我可以使用它吗?

I have access to Bluebird if it will makes things easier?

推荐答案

这是一个创建 Promise.raceAll() 函数的方案,它的工作方式有点像 Promise.all 的组合()Promise.race() 其中承诺都有超时时间和值,因此如果承诺在该时间之前没有解决,它将被短路解决传入的值.这实质上是将每个承诺放入带有计时器的 Promise.race() 中.如果计时器获胜,则使用默认值解析承诺.如果原始承诺获胜,则使用实际承诺结果解决.我们使用 Promise.race() 来解决第一个完成的问题(超时或原始承诺).这是 Promise.race() 的经典用法(事实上,这是我真正使用过它的唯一实际用途).

Here's a scheme that creates a Promise.raceAll() function that works kind of like a combination of Promise.all() and Promise.race() where the promises all have a timeout time and value so that if the promise doesn't resolve before that time, it will be short circuited to resolve with the passed in value. This essentially puts each promise into a Promise.race() with a timer. If the timer wins, the promise is resolved with the default value. If the original promise wins, it's resolved with the actual promise result. We use Promise.race() to resolve with the first one to finish (the timeout or the original promise). This is a classic use for Promise.race() (in fact the only practical use I've ever really used it for).

一个经典的例子是在接下来的 15 秒内为我提供所有的结果.任何需要超过 15 秒的结果,只需为它们返回 null 而不要等待它们.这是使这个概念起作用的代码:

A classic example would be to get me all the results you can in the next 15 seconds. Any results that take longer than 15 seconds, just return null for them and don't wait for them. Here's the code to make this concept work:

Promise.delay = function(t, val) {
    return new Promise(resolve => {
        setTimeout(resolve.bind(null, val), t);
    });
}

Promise.raceAll = function(promises, timeoutTime, timeoutVal) {
    return Promise.all(promises.map(p => {
        return Promise.race([p, Promise.delay(timeoutTime, timeoutVal)])
    }));
}

因此,您可以像使用 Promise.all() 一样使用 Promise.raceAll(),因为您向它传递了一个 promise 数组,但您也向它传递了一个 timeoutTimetimeoutVal.timeoutTime 是承诺超时之前等待的时间.timeoutVal 是为任何超时的承诺放入结果数组的内容(通常它类似于 null ,您可以轻松识别为非真实结果).

So, you use Promise.raceAll() like Promise.all() in that you pass it an array of promises, but you also pass it a timeoutTime and a timeoutVal. The timeoutTime is the how long to wait before timing out the promises. The timeoutVal is what to put in the results array for any promise that timed out (often it will be something like null that you can easily recognize as a non-real result).

我不确定我完全了解您在特定代码中的操作,但这是使用上述内容的 links 代码:

I'm not sure I entirely what you are doing in your specific code, but here's your links code using the above:

Promise.raceAll(links.map(link => {
    return that._$http({
        method: 'GET',
        url: link + '/my/end/point',
        responseType: 'json'
    });
}), 5000, null).then(results => {
    // process results here
    // any timed out values will be null
    // you can filter out the timed out results
    let final = results.filter(item => !!item);
}).catch(err => {
    // process any errors here
});

或者,如果你想确保 Promise.raceAll() 得到所有结果,即使一些承诺被拒绝,你可以添加一个 .catch() 处理程序到每一个承诺:

Or, if you want to make sure Promise.raceAll() gets all results, even if some promises reject, you can add a .catch() handler to each promise:

Promise.raceAll(links.map(link => {
    return that._$http({
        method: 'GET',
        url: link + '/my/end/point',
        responseType: 'json'
    }).catch(err => {
        // don't let Promise.all() see a reject so it gets all results
        return null;
    });
}), 5000, null).then(results => {
    // process results here
    // any timed out values will be null
    // you can filter out the timed out or rejected results
    let final = results.filter(item => !!item);
}).catch(err => {
    // process any errors here
});

这篇关于为 promise.all 中的每个 promise 设置超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆