Führen Sie mehrere Aufgaben asynchron aus und geben Sie das erste erfolgreiche Ergebnis in der JavaScript-Funktion zurück

Ich muss eine JavaScript-Funktion schreiben, die dem Aufrufer einige Daten zurückgibt.

In dieser Funktion habe ich mehrere Möglichkeiten, Daten abzurufen, d. H.

Suche aus dem CacheVon HTML5 LocalStorage abrufenVom REST-Backend abrufen (Bonus: Neue Daten wieder in den Cache stellen)

Das Beenden jeder Option kann einige Zeit in Anspruch nehmen und erfolgreich sein oder fehlschlagen.

Was ich tun möchte, ist, alle diese drei Optionen asynchron / parallel auszuführen und das Ergebnis zurückzugeben, wer zuerst zurückgibt.

Ich verstehe, dass eine parallele Ausführung in JavaScript nicht möglich ist, da es sich um einen Singlethread handelt, aber ich möchte sie zumindest asynchron ausführen und die anderen Tasks abbrechen, wenn eine von ihnen erfolgreich zurückgegeben wird.

Ich habe noch eine Frage.

Vorzeitige Rückkehr und weitere Ausführung der verbleibenden Aufgabe in einer JavaScript-Funktion.

Beispiel Pseudocode:

function getOrder(id) {

    var order;

    // early return if the order is found in cache.
    if (order = cache.get(id)) return order;

    // continue to get the order from the backend REST API.
    order = cache.put(backend.get(id));

    return order;
}

Bitte geben Sie Hinweise zur Implementierung dieser Anforderungen in JavaScript.

Bisher entdeckte Lösungen:Schnellstes ErgebnisJavaScript ES6-Lösung

Ref:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Promise.race (iterabel)

Gibt ein Versprechen zurück, das aufgelöst wird, wenn das erste Versprechen in der Iterationsfolge aufgelöst wird.

var p1 = new Promise(function(resolve, reject) { setTimeout(resolve, 500, "one"); });
var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, "two"); });
Promise.race([p1, p2]).then(function(value) {
  // value == "two"
});
Java / Groovy-Lösung

Ref:http://gpars.org/1.1.0/guide/guide/single.html

import groovyx.gpars.dataflow.Promise
import groovyx.gpars.dataflow.Select
import groovyx.gpars.group.DefaultPGroup
import java.util.concurrent.atomic.AtomicBoolean

/**
 * Demonstrates the use of dataflow tasks and selects to pick the fastest result of concurrently run calculations.
 * It shows a waz to cancel the slower tasks once a result is known
 */

final group = new DefaultPGroup()
final done = new AtomicBoolean()

group.with {
    Promise p1 = task {
        sleep(1000)
        if (done.get()) return
        10 * 10 + 1
    }
    Promise p2 = task {
        sleep(1000)
        if (done.get()) return
        5 * 20 + 2
    }
    Promise p3 = task {
        sleep(1000)
        if (done.get()) return
        1 * 100 + 3
    }

    final alt = new Select(group, p1, p2, p3, Select.createTimeout(500))
    def result = alt.select()
    done.set(true)
    println "Result: " + result
}

Early Return und Interaktive Funktion

Angular Promises kombiniert mit ES6-Generatoren ???
angular.module('org.common')
.service('SpaceService', function ($q, $timeout, Restangular, $angularCacheFactory) {


var _spacesCache = $angularCacheFactory('spacesCache', {
    maxAge: 120000, // items expire after two min
    deleteOnExpire: 'aggressive',
    onExpire: function (key, value) {
        Restangular.one('organizations', key).getList('spaces').then(function (data) {
            _spacesCache.put(key, data);
        });
    }
});
/**
 * @class SpaceService
 */
return {
    getAllSpaces: function (orgId) {
        var deferred = $q.defer();
        var spaces;
        if (spaces = _spacesCache.get(orgId)) {
            deferred.resolve(spaces);
        } else {
            Restangular.one('organizations', orgId).getList('spaces').then(function (data) {
                _spacesCache.put(orgId, data);
                deferred.resolve(data);
            } , function errorCallback(err) {
                deferred.reject(err);
            });
        }
        return deferred.promise;
    },
    getAllSpaces1: function (orgId) {
        var deferred = $q.defer();
        var spaces;
        var timerID = $timeout(
            Restangular.one('organizations', orgId).getList('spaces').then(function (data) {
                _spacesCache.put(orgId, data);
                deferred.resolve(data);
            }), function errorCallback(err) {
                deferred.reject(err);
            }, 0);
        deferred.notify('Trying the cache now...'); //progress notification
        if (spaces = _spacesCache.get(orgId)) {
            $timeout.cancel(timerID);
            deferred.resolve(spaces);
        }
        return deferred.promise;
    },
    getAllSpaces2: function (orgId) {
        // set up a dummy canceler
        var canceler = $q.defer();
        var deferred = $q.defer();
        var spaces;

        $timeout(
            Restangular.one('organizations', orgId).withHttpConfig({timeout: canceler.promise}).getList('spaces').then(function (data) {
                _spacesCache.put(orgId, data);
                deferred.resolve(data);
            }), function errorCallback(err) {
                deferred.reject(err);
            }, 0);


        if (spaces = _spacesCache.get(orgId)) {
            canceler.resolve();
            deferred.resolve(spaces);
        }

        return deferred.promise;
    },
    addSpace: function (orgId, space) {
        _spacesCache.remove(orgId);
        // do something with the data
        return '';
    },
    editSpace: function (space) {
        _spacesCache.remove(space.organization.id);
        // do something with the data
        return '';
    },
    deleteSpace: function (space) {
        console.table(space);
        _spacesCache.remove(space.organization.id);
        return space.remove();
    }
};
});

Antworten auf die Frage(3)

Ihre Antwort auf die Frage