Execute multiple tasks asynchronously and return first successful result in JavaScript function

后端 未结 3 1485
别那么骄傲
别那么骄傲 2021-01-05 16:27

I have to write a javaScript function that return some data to the caller.

In that function I have multiple ways to retrieve data i.e.,

  1. Lookup from ca
3条回答
  •  北荒
    北荒 (楼主)
    2021-01-05 16:51

    Personally, I would try the three asynchronous retrievals sequentially, starting with the least expensive and ending with the most expensive. However, responding to the first of three parallel retrievals is an interesting problem.

    You should be able to exploit the characteristic of $q.all(promises), by which :

    • as soon as any of the promises fails then the returned promise is rejected
    • if all promises are successful then the returned promise is resolved.

    But you want to invert the logic such that :

    • as soon as any of the promises is successful then the returned promise is resolved
    • if all promises fail then the returned promise is rejected.

    This should be achievable with an invert() utility which converts success to failure and vice versa.

    function invert(promise) {
        return promise.then(function(x) {
            return $q.defer().reject(x).promise;
        }, function(x) {
            return $q.defer().resolve(x).promise;
        });
    }
    

    And a first() utility, to give the desired behaviour :

    function first(arr) {
        return invert($q.all(arr.map(invert)));
    }
    

    Notes:

    • the input arr is an array of promises
    • a native implementation of array.map() is assumed (otherwise you can explicitly loop to achieve the same effect)
    • the outer invert() in first() restores the correct sense of the promise it returns
    • I'm not particularly experienced in angular, so I may have made syntactic errors - however I think the logic is correct.

    Then getOrder() will be something like this :

    function getOrder(id) {
        return first([
            cache.get(id),
            localStorage.get(id).then(cache.put),
            backend.get(id).then(cache.put).then(localStorage.put)
        ]);
    }
    

    Thus, getOrder(id) should return a Promise of an order (not the order directly).

提交回复
热议问题