javascript - How to resolve a variable number of promises in node.js -


i'm working on function (called express.js route) merge event info in database facebook counterpart , return array of event objects.

i having trouble asynchronous nature of node.js , resolving variable number of promises within foreach loop before returning whole object. i've tried numerous different methods of rearranging code (callbacks, counters, promises, etc.), have not been successful in solving problem, , know why. suspect has variables being overwritten in foreach loop, i'm not sure how solve that.

i looking 3 things:

  1. what not grasping conceptually needed solve problem?
  2. how figure out or debug in future?
  3. how fix code make work?

here 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);          (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... promises haven't resolved                     //...                     dfd.resolve(events);                 });             }         }     }else{         console.log("not authenticated. redirecting main page.");         dfd.resolve(events);     } });  return dfd.promise;  } 

while trying json object, returns unresolved promise on console.log(results[0]):

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

code references have viewed:

oh, , here's function single event fb/db merge works, can compare:

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. redirecting main page");         dfd.resolve(event);     } });  return dfd.promise; } 

your main problem here:

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

q.defer() not return promise. returns deferred.

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

naming variables correctly important, didn't see mistake because chose improper variable names.


that being said...

  • avoid for .. in. arrays have .foreach() or .map().
  • instead of checking if (promises.length == events.length), move part out of loop.
  • your function pretty long , use little refactoring.
  • and of course, don't call deferred objects "deferred" or promise objects "promise". that's not descriptive.
  • read through what explicit promise construction antipattern , how avoid it? (let sink in, takes time)

here's use.

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 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...         }));     }); } 

note: if wrote ensureauthenticated, modify reject directly , on own instead of resolving falsy auth value need check every time use it. line if (!auth) ... removed after that.

also, //more code in here... part deals "enhanced" events should probably live outside of mergeevents.


Popular posts from this blog

c# - ODP.NET Oracle.ManagedDataAccess causes ORA-12537 network session end of file -

matlab - Compression and Decompression of ECG Signal using HUFFMAN ALGORITHM -

utf 8 - split utf-8 string into bytes in python -