reject node new all javascript node.js promise bluebird

javascript - node - callback to promise bluebird



Forma correcta de escribir bucles para promesas. (10)

No creo que garantice el orden de llamar a logger.log (res);

En realidad, lo hace. Esa declaración se ejecuta antes de la llamada de resolve .

¿Alguna sugerencia?

Un montón. Lo más importante es tu uso del antipatrón de crear-prometer-manualmente , solo hazlo

promiseWhile(…, function() { return db.getUser(email) .then(function(res) { logger.log(res); count++; }); })…

Segundo, eso while que la función podría simplificarse mucho:

var promiseWhile = Promise.method(function(condition, action) { if (!condition()) return; return action().then(promiseWhile.bind(null, condition, action)); });

En tercer lugar, no usaría un ciclo while (con una variable de cierre) sino un ciclo for :

var promiseFor = Promise.method(function(condition, action, value) { if (!condition(value)) return value; return action(value).then(promiseFor.bind(null, condition, action)); }); promiseFor(function(count) { return count < 10; }, function(count) { return db.getUser(email) .then(function(res) { logger.log(res); return ++count; }); }, 0).then(console.log.bind(console, ''all done''));

¿Cómo construir correctamente un ciclo para asegurarse de que la siguiente llamada promisoria y el archivo logger.log (res) encadenados se ejecuten de forma sincronizada a través de la iteración? (azulejo)

db.getUser(email).then(function(res) { logger.log(res); }); // this is a promise

Intenté de la siguiente manera (método de http://blog.victorquinn.com/javascript-promise-while-loop )

var Promise = require(''bluebird''); var promiseWhile = function(condition, action) { var resolver = Promise.defer(); var loop = function() { if (!condition()) return resolver.resolve(); return Promise.cast(action()) .then(loop) .catch(resolver.reject); }; process.nextTick(loop); return resolver.promise; }); var count = 0; promiseWhile(function() { return count < 10; }, function() { return new Promise(function(resolve, reject) { db.getUser(email) .then(function(res) { logger.log(res); count++; resolve(); }); }); }).then(function() { console.log(''all done''); });

Aunque parece funcionar, pero no creo que garantice el orden de llamar a logger.log (res);

¿Alguna sugerencia?


¿Qué tal este utilizando BlueBird ?

function fetchUserDetails(arr) { return Promise.each(arr, function(email) { return db.getUser(email).done(function(res) { logger.log(res); }); }); }


Aquí hay otro método (ES6 w / std Promise). Utiliza los criterios de salida del tipo lodash / underscore (return === false). Tenga en cuenta que puede agregar fácilmente un método exitIf () en las opciones para ejecutar en doOne ().

const whilePromise = (fnReturningPromise,options = {}) => { // loop until fnReturningPromise() === false // options.delay - setTimeout ms (set to 0 for 1 tick to make non-blocking) return new Promise((resolve,reject) => { const doOne = () => { fnReturningPromise() .then((...args) => { if (args.length && args[0] === false) { resolve(...args); } else { iterate(); } }) }; const iterate = () => { if (options.delay !== undefined) { setTimeout(doOne,options.delay); } else { doOne(); } } Promise.resolve() .then(iterate) .catch(reject) }) };


Así es como lo hago con el objeto Promesa estándar.

// Given async function sayHi function sayHi() { return new Promise((resolve) => { setTimeout(() => { console.log(''Hi''); resolve(); }, 3000); }); } // And an array of async functions to loop through const asyncArray = [sayHi, sayHi, sayHi]; // We create the start of a promise chain let chain = Promise.resolve(); // And append each function in the array to the promise chain for (const func of asyncArray) { chain = chain.then(func); } // Output: // Hi // Hi (After 3 seconds) // Hi (After 3 more seconds)


Haría algo como esto:

var request = [] while(count<10){ request.push(db.getUser(email).then(function(res) { return res; })); count++ }; Promise.all(request).then((dataAll)=>{ for (var i = 0; i < dataAll.length; i++) { logger.log(dataAll[i]); } });

de esta manera, dataAll es una matriz ordenada de todos los elementos para el registro. Y la operación de registro funcionará cuando se cumplan todas las promesas.



La función sugerida por Bergi es realmente agradable:

var promiseWhile = Promise.method(function(condition, action) { if (!condition()) return; return action().then(promiseWhile.bind(null, condition, action)); });

Aún así, quiero hacer una pequeña adición, lo que tiene sentido, cuando se usan promesas:

var promiseWhile = Promise.method(function(condition, action, lastValue) { if (!condition()) return lastValue; return action().then(promiseWhile.bind(null, condition, action)); });

De esta forma, el ciclo while puede insertarse en una cadena de promesas y resuelve con lastValue (también si la acción () nunca se ejecuta). Ver ejemplo:

var count = 10; util.promiseWhile( function condition() { return count > 0; }, function action() { return new Promise(function(resolve, reject) { count = count - 1; resolve(count) }) }, count)


Si realmente quiere una promiseWhen() general promiseWhen() funcione para este y otros fines, entonces hágalo de todos modos, utilizando las simplificaciones de Bergi. Sin embargo, debido a la forma en que funcionan las promesas, pasar devoluciones de llamada de esta manera es generalmente innecesario y te obliga a saltar a través de pequeños aros complejos.

Por lo que puedo decir, estás intentando:

  • para obtener asincrónicamente una serie de detalles de usuario para una colección de direcciones de correo electrónico (al menos, ese es el único escenario que tiene sentido).
  • para hacerlo, construyendo una cadena .then() través de la recursión.
  • para mantener el orden original al manejar los resultados devueltos.

Definido así, el problema es en realidad el que se analiza en "The Collection Kerfuffle" en Promise Anti-patterns , que ofrece dos soluciones simples:

  • llamadas asincrónicas paralelas usando Array.prototype.map()
  • llamadas asincrónicas en serie usando Array.prototype.reduce() .

El enfoque paralelo proporcionará (de manera directa) el problema que intenta evitar: que el orden de las respuestas sea incierto. El enfoque en serie construirá la cadena .then() requerida - plana - sin recurrencia.

function fetchUserDetails(arr) { return arr.reduce(function(promise, email) { return promise.then(function() { return db.getUser(email).done(function(res) { logger.log(res); }); }); }, Promise.resolve()); }

Llame de la siguiente manera:

//Compose here, by whatever means, an array of email addresses. var arrayOfEmailAddys = [...]; fetchUserDetails(arrayOfEmailAddys).then(function() { console.log(''all done''); });

Como puede ver, no hay necesidad de contar la varita externa fea o su función de condition asociada. El límite (de 10 en la pregunta) está completamente determinado por la longitud de la matriz arrayOfEmailAddys .


Dado

  • función asyncFn
  • conjunto de elementos

Necesario

  • Promete encadenar .then () en serie (en orden)
  • es6 nativo

Solución

let asyncFn = (item) => { return new Promise((resolve, reject) => { setTimeout( () => {console.log(item); resolve(true)}, 1000 ) }) } // asyncFn(''a'') // .then(()=>{return async(''b'')}) // .then(()=>{return async(''c'')}) // .then(()=>{return async(''d'')}) let a = [''a'',''b'',''c'',''d''] a.reduce((previous, current, index, array) => { return previous // initiates the promise chain .then(()=>{return asyncFn(array[index])}) //adds .then() promise for each item }, Promise.resolve())


function promiseLoop(promiseFunc, paramsGetter, conditionChecker, eachFunc, delay) { function callNext() { return promiseFunc.apply(null, paramsGetter()) .then(eachFunc) } function loop(promise, fn) { if (delay) { return new Promise(function(resolve) { setTimeout(function() { resolve(); }, delay); }) .then(function() { return promise .then(fn) .then(function(condition) { if (!condition) { return true; } return loop(callNext(), fn) }) }); } return promise .then(fn) .then(function(condition) { if (!condition) { return true; } return loop(callNext(), fn) }) } return loop(callNext(), conditionChecker); } function makeRequest(param) { return new Promise(function(resolve, reject) { var req = https.request(function(res) { var data = ''''; res.on(''data'', function (chunk) { data += chunk; }); res.on(''end'', function () { resolve(data); }); }); req.on(''error'', function(e) { reject(e); }); req.write(param); req.end(); }) } function getSomething() { var param = 0; var limit = 10; var results = []; function paramGetter() { return [param]; } function conditionChecker() { return param <= limit; } function callback(result) { results.push(result); param++; } return promiseLoop(makeRequest, paramGetter, conditionChecker, callback) .then(function() { return results; }); } getSomething().then(function(res) { console.log(''results'', res); }).catch(function(err) { console.log(''some error along the way'', err); });