2017-04-08 2 views
0

Ich versuche, jedem Element eines Arrays einige zusätzliche Werte hinzuzufügen. Also habe ich ein Array mit Objekten und sie haben: x, y und z Felder. Ich möchte dann zu jedem Objekt im Array zusätzliche Elemente basierend auf der Antwort eines http.get-Aufrufs hinzufügen.ForEach aktualisiert Hauptarray nicht

Haupt Array ist: Beiträge

Siehe Code unten:

router.get('/api/posts', function(req, res){ 

    postModel.find({}) 
     .limit(10) 
     .exec(function(err, posts) { 
      var options = { 
       host: 'localhost', 
       port: 3000, 
       path: '/user?id=12345678', 
       method: 'GET' 
      }; 
      if(posts){ 
       posts.forEach(function(post) { 

        var req = http.get(options, function(res) { 
         var bodyChunks = []; 
         res.on('data', function(chunk) { 
          bodyChunks.push(chunk); 
         }).on('end', function() { 
          var body = Buffer.concat(bodyChunks); 
          var parsedBody = JSON.parse(body); 
          post.fullname = parsedBody.user.fullname; 
          post.profilePic = parsedBody.user.profilePic; 
         }); 
        });  
       }); 
      res.json({ 
       posts  : posts 
      }); 
      } else { 
       res.send('Post does not exist'); 
      } 
     }); 
}); 

Zum Zeitpunkt des post.profilePic = parsedBody.user.profilePic - die profilePic Variable ist aber wenn ich eine Antwort vom Knoten über res.json bekomme, sind die zusätzlichen Werte nicht.

Was fehlt mir hier? Ich benutze diesen Ansatz mit meinem Angular Frontend die ganze Zeit ohne ein Problem.

Dank

+0

Versuchen Sie eins: weisen Sie einer Variable 'var temp = post'' post' zu. Fügen Sie 'fullname' und' profilePic' zu dieser Variablen 'temp.fullname = parsedBody.user.fullname;' und 'post.profilePic = parsedBody.user.profilePic' hinzu. Gib nun 'temp' anstelle von' posts' zurück. –

+0

Danke für den Kommentar. Dieser Ansatz wird funktionieren, aber sicherlich gibt es einen nativeren Weg richtig? Ich werde zu dem Array pushen müssen, wo die meisten Daten bereits da sind, was zu einem enormen Overhead im Speicher führen wird (die realen Daten sind riesig). –

Antwort

2

sein sollten Dies ist ein unglaublich weit verbreitetes Problem, Sie behandeln asynchronen Code, als ob es synchron waren. http.get wird nicht sofort abgeschlossen, noch wird der Code daran gehindert, weiterzumachen, daher wird res.json aufgerufen, bevor Ihre Anforderungen abgeschlossen sind. Es gibt eine Menge Möglichkeiten, dies zu beheben, werde ich meinen Favoriten - Javascript Promises.

// use map instead of forEach to transform your array 
// of posts into an array of promises 
var postPromises = posts.map(function(post) { 
    return new Promise(function(resolve) { 
    var req = http.get(options, function(res) { 
     var bodyChunks = []; 
     res.on('data', function(chunk) { 
      bodyChunks.push(chunk); 
     }).on('end', function() { 
      var body = Buffer.concat(bodyChunks); 
      var parsedBody = JSON.parse(body); 
      post.fullname = parsedBody.user.fullname; 
      post.profilePic = parsedBody.user.profilePic; 
      // resolve the promise with the updated post 
      resolve(post); 
     }); 
    }); 
    }); 
}); 

// once all requests complete, send the data 
Promise.all(postPromises).then(function(posts) { 
    res.json({ 
    posts: posts 
    }); 
}); 
+0

Ah einer dieser wieder! Ich hasse es, wie ich immer in ihnen gefangen bin. Danke, Rob. Das hat für mich wie ein Zauber gewirkt! –

+0

großartig ... es ist wirklich das Beste ... –

0

Knoten arbeiten nach Rückrufe. Sie Callbacks, die nicht in der forEach-Schleife abgeschlossen werden, und Sie geben Antwort auf Benutzer. Das ist das Problem.

Schreiben Sie Code für das kann ich Lösung vorschlagen.

router.get('/api/posts', function(req, res){ 

    postModel.find({}) 
     .limit(10) 
     .exec(function(err, posts) { 
      var options = { 
       host: 'localhost', 
       port: 3000, 
       path: '/user?id=12345678', 
       method: 'GET' 
      }; 
      if(posts){ 
       var EventEmitter = require('events'); 
       var HttpEvent = new EventEmitter(); 
       let counts = 0; 
       let length = posts.length; 

       posts.forEach(function(post) { 

        var req = http.get(options, function(res) { 
         var bodyChunks = []; 
         res.on('data', function(chunk) { 
          bodyChunks.push(chunk); 
         }).on('end', function() { 
          var body = Buffer.concat(bodyChunks); 
          var parsedBody = JSON.parse(body); 
          posts.fullname = parsedBody.user.fullname; 
          posts.profilePic = parsedBody.user.profilePic; 
          HttpEvent.emit('done'); 
         }); 
        });  
       }); 

       HttpEvent.on('done',()=>{ 
        counts += 1; 
        if(counts == length){ 
         res.json({ 
          posts  : posts 
         }); 
        } 
       }) 

      } else { 
       res.send('Post does not exist'); 
      } 
     }); 
}); 

Noch eine falsche Sache, die Sie tun, ist

post.fullname = parsedBody.user.fullname; 
post.profilePic = parsedBody.user.profilePic; 

Es

posts.fullname = parsedBody.user.fullname; 
posts.profilePic = parsedBody.user.profilePic; 
+0

Danke für den Kommentar. Ich habe es einfach versucht, aber es hat nicht funktioniert. Die zurückgegebenen Daten haben immer noch keine Werte. Auch für den ** post.fullname = parsedBody.user.fullname; ** - wird es auf diese Weise benannt, da es Teil der Schleife ist. Ich passe ** post ** im forEach –

Verwandte Themen