MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Pourquoi est-ce que je reçois Impossible de définir les en-têtes après leur envoi au client erreur dans Nodejs ?

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