Execute várias tarefas de forma assíncrona e retorne o primeiro resultado bem-sucedido na função JavaScript
Eu tenho que escrever uma função javaScript que retorne alguns dados para o chamador.
Nessa função, tenho várias maneiras de recuperar dados, ou seja,
Pesquisa do cacheRecuperar do HTML5 LocalStorageRecuperar do REST Backend (bônus: coloque os dados atualizados novamente em cache)Cada opção pode levar algum tempo para terminar e pode ter êxito ou falhar.
O que eu quero fazer é executar todas essas três opções de forma assíncrona / paralela e retornar o resultado quem retornar primeiro.
Entendo que a execução paralela não é possível no JavaScript, pois é de thread único, mas quero pelo menos executá-las de forma assíncrona e cancelar as outras tarefas se uma delas retornar resultado com êxito.
Eu tenho mais uma pergunta.
Retorne antecipadamente e continue executando a tarefa restante em uma função JavaScript.
Exemplo de pseudocódigo:
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;
}
Aconselhe como implementar esses requisitos em JavaScript.
Soluções descobertas até agora:Resultado mais rápidoSolução JavaScript ES6Ref:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Promise.race (iterável)
Retorna uma promessa que resolve quando a primeira promessa no iterável é resolvida.
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"
});
Solução Java / GroovyRef: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
}
Retorno Antecipado e Função Interativa
Promessas angulares combinadas com geradores 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();
}
};
});