w3schools then promises promesas funciones example encadenar anidadas javascript promise

then - Encadenamiento dinámico en las promesas de Javascript



promise typescript (8)

¿Cómo puedo realizar el encadenamiento dinámico en las promesas de Javascript, siempre he visto solo codificación de las llamadas, por ejemplo, (promise).then(request/functionName).then(request/functionName)


Acabo de tener un problema con mi proveedor de api que al hacer Promise.all () terminaría en problemas de db de concurrencia ...

El trato con mi situación es que necesito obtener el resultado de cada promesa para mostrar una alerta de "todo bien" o "algún error".

Y no sé por qué ... este pequeño trozo de código que usa se reduce cuando las promesas se resuelven, no pude hacer funcionar mi alcance (demasiado tarde para investigar ahora)

$scope.processArray = function(array) { var results = []; return array.reduce(function(p, i) { return p.then(function() { return i.then(function(data) { results.push(data); return results; }) }); }, Promise.resolve()); }

Así que gracias a este post http://hellote.com/dynamic-promise-chains/ Vine con este pequeño bastardo ... No está pulido pero está funcionando bien.

$scope.recurse = function(promises, promisesLength, results) { if (promisesLength === 1) { return promises[0].then(function(data){ results.push(data); return results; }); } return promises[promisesLength-1].then(function(data) { results.push(data); return $scope.recurse(promises, promisesLength - 1, results); }); }

Entonces invoco la función así:

var recurseFunction = $scope.recurse(promises, promises.length, results); recurseFunction.then(function (response) { ... });

Espero que ayude.



Creo que la forma más sencilla es:

const executePromises = function(listOfProviders){ const p = Promise.resolve(null); for(let i = 0; i < listOfProviders.length; i++){ p = p.then(v => listOfProviders[i]()); } return p; };

Creo que lo anterior es básicamente equivalente a:

const executePromises = async function(listOfProviders) { for(let i = 0; i < listOfProviders.length; i++){ await listOfProviders[i](); } };


Dadas las funciones de una matriz que todas devuelven promesas, puede usar reduce() para ejecutarlas secuencialmente:

var myAsyncFuncs = [ function (val) {return Promise.resolve(val + 1);}, function (val) {return Promise.resolve(val + 2);}, function (val) {return Promise.resolve(val + 3);}, ]; myAsyncFuncs.reduce(function (prev, curr) { return prev.then(curr); }, Promise.resolve(1)) .then(function (result) { console.log(''RESULT is '' + result); // prints "RESULT is 7" });

El ejemplo anterior utiliza Promesas de ES6 pero todas las bibliotecas de promesa tienen características similares.

Además, la creación de la matriz de funciones de devolución de promesa suele ser un buen candidato para usar map() . Por ejemplo:

myNewOrmModels.map(function (model) { return model.save.bind(model); }).reduce(function (prev, curr) { return prev.then(curr); }, Promise.resolve()) .then(function (result) { console.log(''DONE saving''); });


Dado que las promesas se desenvuelven, simplemente continúe agregando declaraciones y continuará encadenándose

function asyncSeries(fns) { return fns.reduce(function(p, fn) { return p.then(fn); }, Promise.resolve()); }

Recursivamente es una manera muy buena de hacerlo también :)

function countTo(n, sleepTime) { return _count(1); function _count(current) { if (current > n) { return Promise.resolve(); } return new Promise(function(resolve, reject) { console.info(current); setTimeout(function() { resolve(_count(current + 1)); }, sleepTime); }); } }


Esta es la forma ES7.

Digamos que tienes múltiples promesas definidas en una matriz.

var funcs = [ _ => new Promise(res => setTimeout(_ => res("1"), 1000)), _ => new Promise(res => setTimeout(_ => res("2"), 1000)) }

Y quieres llamar así.

chainPromises(funcs).then(result => console.log(result));

Puede utilizar async y await para este propósito.

async function chainPromises(promises) { for (let promise of promises) { // must be for (.. of ..) await promise(); } }

Esto ejecutará las funciones dadas secuencialmente (una por una), no en paralelo. El parámetro promises es una serie de funciones que devuelven Promise .

Plunker: http://plnkr.co/edit/UP0rhD?p=preview


Esta solución basada en promesas de uso se introdujo en EcmaScript 6 ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise ), así que antes de usarla, consulte el soporte del navegador de tablas https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Browser_compatibility

Código

var f1 = function(){ for (var i = 0; i < 800000000; i++) {} console.log(''Function1 is done''); } var f2 = function(){ for (var i = 0; i < 800000000; i++) {} console.log(''Function2 is done''); } var f3 = function(){ for (var i = 0; i < 800000000; i++) {} console.log(''Function3 is done''); } var f4 = function(){ for (var i = 0; i < 800000000; i++) {} console.log(''Function4 is done''); } callbacks = function(){ // copy passed arguments var callbacks = arguments; // create array functions var callbacks = Object.keys(callbacks).map(function(el){ return callbacks[el] }); var now = Date.now(); callbacks.reduce(function(previousPromise, currentFunc){ return previousPromise.then( function(){ currentFunc(); var seconds = (Date.now() - now) / 1000; console.log(''Gone'', seconds, ''seconds''); } ) }, Promise.resolve()); } callbacks(f1, f2, f3, f4);

Resultado en la consola de Chrome (los valores de segundos serán diferentes):

Function1 is done Gone 1.147 seconds Function2 is done Gone 2.249 seconds Function3 is done Gone 3.35 seconds Function4 is done Gone 4.47 seconds

Notas:

  1. No funciona si una función contiene un temporizador (para este problema también intento jQuery`s $ Callbacks, $ .Ajax y $ .When, pero no es útil. La única decisión, lo que encontré, use resolver () en callback de un temporizador, pero no es aceptable si ha completado las funciones.).
  2. Entorno de prueba

$ google-chrome --version Google Chrome 53.0.2785.116


Una opción es utilizar las propiedades de los objetos y la capacidad de invocarlos a través de cadenas.

Escribí una pequeña muestra Here y la publiqué a continuación.

La idea es que tenga el conjunto de funciones que desea ejecutar en algún espacio de nombres u objeto, como hice en ''myNamespace'':

myNamespace = { "A": function() {return "A Function";}, "B": function() {return "B Function";}, "C": function() {return "C Function";} }

Entonces su promesa principal se ejecutaría y de alguna manera (a través de entradas, ajax, indicaciones, etc.) obtendría el valor de cadena de la función que desea ejecutar, que no se conoce hasta el tiempo de ejecución:

Mi promesa principal utiliza un mensaje para obtener una carta del usuario:

var answer = prompt(''Starting. Please pick a letter: A,B,C''); if(myNamespace[answer] === undefined) { alert("Invalid choice!"); reject("Invalid choice of: " + answer); } else { resolve(answer); }

En el siguiente ''entonces'' uso ese valor (pasado a través de la función de resolución) para invocar la función:

.then(function(response) { funcToRun = myNamespace[response]();})

Finalmente, muestro a html el resultado de mi llamada a la función dinámica y uso algo de diversión recursiva para hacerlo más interactivo y demostrar que es dinámico:

.then(function(){ document.getElementById(''result'').innerHTML = funcToRun;}) .then(function(){ if(prompt("Run Again? (YES/NO)")==="YES") { doWork(); } });

myNamespace = { "A": function() {return "A Function";}, "B": function() {return "B Function";}, "C": function() {return "C Function";} } function doWork() { var funcToRun; new Promise(function(resolve,reject) { var answer = prompt(''Starting. Please pick a letter: A,B,C''); if(myNamespace[answer] === undefined) { alert("Invalid choice!"); reject("Invalid choice of: " + answer); } else { resolve(answer); } }) .then(function(response) { funcToRun = myNamespace[response]();}) .then(function(){ document.getElementById(''result'').innerHTML = funcToRun;}) .then(function(){ if(prompt("Run Again? (YES/NO)")==="YES") { doWork(); } }); } doWork();

<div id="result"></div>