Juste ici :
Post.find({}, function(err, docs) {
if (docs.length == 0)
return res.send({ message: "No posts" });
Si vous remplissez cette condition de docs.length == 0
, vous enverrez alors une réponse à la demande. Mais, votre return
revient UNIQUEMENT du Post.find()
rappeler. Il ne revient pas de votre trendingposts()
fonction.
Donc, pendant ce temps, cette fonction continue de s'exécuter et finit par arriver à ce code :
var mysort = { score: -1 };
Post.find({})
.populate("postedBy")
.populate("comments.postedBy")
.populate("comments.incomments.postedBy")
.populate("comments.likes")
.sort(mysort)
.limit(10)
.exec((er, result) => {
res.json(result);
});
Où vous envoyez ensuite une autre réponse à la même demande. C'est ce qui déclenche l'erreur Cannot set headers after they are sent to the client
que vous voyez.
Il existe de nombreuses façons d'éviter cela, mais elles sont probablement toutes liées à la façon dont vous nettoyez généralement cette fonction. La façon dont il est écrit maintenant, vous démarrez essentiellement deux chemins de code asynchrones complètement séparés. Les deux commencent par Post.find({})
et partir de là. Ils s'exécutent chacun en parallèle et aucun n'a la moindre idée de ce que fait l'autre chemin de code. En tant que tel, vous n'avez aucun moyen concret d'envoyer une réponse d'un, mais pas des deux.
Ainsi, la façon de nettoyer cela est probablement de ne pas avoir deux chemins de code asynchrones complètement séparés. Vous devez les coordonner d'une manière ou d'une autre. Dans à peu près tous les cas ici, vous souhaiterez passer à l'interface promise de votre base de données car cela vous donnera beaucoup plus d'options pour gérer votre flux de contrôle. Par exemple, si pour des raisons de performances, vous souhaitez avoir deux opérations asynchrones parallèles en même temps, avec des promesses, vous pouvez utiliser Promise.all()
ou Promise.allSettled()
pour surveiller les deux et savoir quand ils sont terminés, puis, avec les deux résultats en main, décider quelle réponse envoyer.
Ou, si vous voulez les séquencer, vous pouvez utiliser async/await
pour enchaîner assez facilement les deux opérations puis quand on fait un return
, il reviendra en fait de la fonction de niveau supérieur et arrêtera tout autre flux de contrôle.
Si vous voulez vous en tenir à l'interface de rappel de votre base de données, vous devrez probablement imbriquer la deuxième opération dans la première option afin de ne pas démarrer la deuxième opération si vous allez faire res.send({ message: "No posts" })
.