Выполнить несколько задач асинхронно и вернуть первый успешный результат в функции JavaScript
Я должен написать функцию javaScript, которая возвращает некоторые данные вызывающей стороне.
В этой функции у меня есть несколько способов получения данных, т.е.
Поиск из кэшаПолучить из HTML5 LocalStorageПолучить из REST Backend (бонус: положить свежие данные обратно в кеш)Каждый вариант может занять свое время, чтобы завершиться, и он может быть успешным или неудачным.
Что я хочу сделать, так это выполнить все эти три параметра асинхронно / параллельно и вернуть результат тому, кто вернется первым.
Я понимаю, что параллельное выполнение невозможно в JavaScript, поскольку оно является однопоточным, но я хочу, по крайней мере, выполнить их асинхронно и отменить другие задачи, если одна из них вернет результат успешно.
У меня есть еще один вопрос.
Ранний возврат и продолжение выполнения оставшейся задачи в функции JavaScript.
Пример псевдокода:
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;
}
Пожалуйста, посоветуйте, как реализовать эти требования в JavaScript.
Решения, обнаруженные до сих пор:Самый быстрый результатРешение JavaScript ES6Ref:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Promise.race (итерация)
Возвращает обещание, которое разрешается, когда первое обещание в итерируемом разрешается.
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 решение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
}
Раннее возвращение и интерактивная функция
Угловые обещания в сочетании с генераторами ES6 ???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();
}
};
});