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 .

  • Q promise: ¿se invocan las devoluciones de llamada en el mismo order en que se registraron?
  • Cómo encadenar correctamente las promises condicionales (?) Con Q.js
  • Saltarse cadena de promise después de manejar el error
  • encadenando promises con q.js
  • Comparación de biblioteca asíncrona Node.js - Q vs Async
  • La mejor práctica para encadenar promises en Nodejs / Express
  • Dificultad para ajustar un comportamiento de javascript y mantenerlo para más tarde
  • ¿Cuál es la diferencia entre la biblioteca de Q Promise .finally () y .done ()?
  • Javascript tiene muchos buenos JS marco (como Node.js AngularJS Vue.js React.js) es el mejor lenguaje de script.