Cómo resolver una cantidad variable de promises en node.js

Estoy trabajando en una function (llamada mediante una ruta express.js) para fusionar la información del evento en una database con su contraparte de Facebook y devolverla como una matriz de objects de evento.

Tengo problemas con la naturaleza asíncrona de node.js y la resolución de un número variable de promises dentro de un ciclo foreach antes de devolver todo el object. He intentado numerosos methods diferentes de reorganizar mi código (devoluciones de llamada, contadores, promises, etc.), pero no he tenido éxito en la solución de este problema, y ​​realmente me gustaría saber por qué. Sospecho que tiene que ver con que las variables se sobrescriban en el ciclo foreach, pero no estoy seguro de cómo resolverlo.

Estoy buscando tres cosas:

  1. ¿Qué no estoy entendiendo conceptualmente que es necesario para resolver este problema?
  2. ¿Cómo podría solucionar esto o corregir esto en el futuro?
  3. ¿Cómo arreglo mi código para que funcione?

Aquí está mi function:

function mergeEvents(req, res, next, events){ console.log("Merge Events"); var dfd = q.defer(); ensureAuthenticated(req, res, next).then(function(auth){ var iEvent, event; var promises = []; if (auth){ console.log("authenticated!"); console.log("auth token: " + ACCESS_TOKEN); for (iEvent in events){ event = events[iEvent]; var promise = q.defer(); promises.push(promise); https.get('https://graph.facebook.com/' + event.fb_id + '?access_token=' + ACCESS_TOKEN, function(response) { var str = ''; response.on('data', function(chunk){ str += chunk; }); response.on('end', function(){ var fb_event = JSON.parse(str); event.dataValues.fb = fb_event; promise.resolve(event); }); }); if (promises.length == events.length){ console.log("last run through"); q.all(promises).then(function(results){ console.log("all promises completed?"); console.log(results[0]); //OUTPUT BELOW //more code in here... but promises haven't resolved //... dfd.resolve(events); }); } } }else{ console.log("Not authenticated. Redirecting to main page."); dfd.resolve(events); } }); return dfd.promise; } 

Mientras trato de get un object JSON, devuelve una promise no resuelta en console.log (resultados [0]):

 { promise: [object Object], resolve: [Function], fulfill: [Function], reject: [Function], notify: [Function] } 

Referencias de código que he visto:

  • https://github.com/kriskowal/q
  • https://github.com/kriskowal/q/wiki/API-Reference
  • https://strongloop.com/strongblog/how-to-compose-node-js-promises-with-q/
  • http://thejsguy.com/javascript/node.js/2014/06/27/JavaScript-Flow-Control.html

Ah, y aquí está mi function para un solo evento fb / db merge que funciona, para que pueda comparar:

 function mergeEvent(req, res, next, event){ console.log("Merge Event"); var dfd = q.defer(); ensureAuthenticated(req, res, next).then(function(auth){ if (auth){ console.log("authenticated!"); console.log("auth token: " + ACCESS_TOKEN); https.get('https://graph.facebook.com/' + event.fb_id + '?access_token=' + ACCESS_TOKEN, function(response) { var str = ''; response.on('data', function(chunk){ str += chunk; }); response.on('end', function(){ var fb_event = JSON.parse(str); event.dataValues.fb = fb_event; dfd.resolve(event); }); }); }else{ console.log("not authenticated. networkingirecting to main page"); dfd.resolve(event); } }); return dfd.promise; } 

One Solution collect form web for “Cómo resolver una cantidad variable de promises en node.js”

Tu problema principal está aquí:

 var promise = q.defer(); promises.push(promise); 

q.defer() no devuelve una promise. Devuelve un diferido .

 var result = q.defer(); promises.push(result.promise); 

Nombrar variables correctamente es importante, no vio el error porque eligió nombres de variable incorrectos.


Habiendo dicho eso…

  • Evitar for .. in Las matrices tienen .forEach() o .map() .
  • En lugar de verificar if (promises.length == events.length) , mueve esa parte fuera del ciclo.
  • Su function es bastante larga y podría usar un poco de refactorización.
  • Y, por supuesto, no llame "diferida" a sus objects diferidos ni a sus objects prometidos como "promises". Eso no es descriptivo.
  • Lea atentamente ¿Cuál es el antipatrón de construcción de promise explícita y cómo lo evito? (deja que se hunda, lleva algo de time)

Esto es lo que usaría.

 var q = require('q'); var qHttp = require("q-io/http"); // -> https://github.com/kriskowal/q-io var FB = { // collect other FB API methods here, maybe transform into module graph: function (id) { var url = 'https://graph.facebook.com/' + id + '?access_token=' + ACCESS_TOKEN; return qHttp.read(url).then(function (data) { return JSON.parse(data.toString()); }); } }; function mergeEvents(req, res, next, events) { return ensureAuthenticated(req, res, next).then(function (auth) { if (!auth) return q.reject("Not authenticated."); return q.all(events.map(function (event) { return FB.graph(event.fb_id).then(function (data) { event.dataValues.fb = data; return event; }); }).then(function (results) { //more code in here... })); }); } 

Nota: Si escribió ensureAuthenticated , ensureAuthenticated para rechazarlo directamente y por sí mismo en lugar de resolver con un valor de auth falso que debe verificar cada vez que lo use. La línea if (!auth) ... podría eliminarse después de eso.

Además, el //more code in here... parte que trata con los events "mejorados" probablemente debería vivir fuera de mergeEvents .

  • ¿Por qué la promise todavía está pendiente?
  • Uso de promises: rastreo de la stack de logging en el controller de fallas
  • Motivos de rechazo no controlados (deben estar vacíos)
  • AngularJS Promises, $ q, diferir
  • Protables: repita la operación hasta que tenga éxito?
  • Resolver promete uno tras otro (es decir, en secuencia)?
  • Límite de concurrency en promises Q - nodo
  • Reemplazar devoluciones de llamada con promises en Node.js
  • Q: ejecutar una serie de promises y definir dependencies entre ellas en un DAG
  • Protables de deshilachado en Javascript
  • Bluebird promisifica múltiples arguments
  • Javascript tiene muchos buenos JS marco (como Node.js AngularJS Vue.js React.js) es el mejor lenguaje de script.