Här:
Post.find({}, function(err, docs) {
if (docs.length == 0)
return res.send({ message: "No posts" });
Om du träffar villkoret docs.length == 0
, så skickar du ett svar på begäran. Men din return
returnerar ENDAST från Post.find()
ring tillbaka. Det kommer inte tillbaka från dina trendingposts()
funktion.
Så under tiden fortsätter den funktionen att köras och kommer så småningom till den här koden:
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);
});
Där du sedan skickar ett annat svar på samma förfrågan. Det är det som utlöser felet Cannot set headers after they are sent to the client
som du ser.
Det finns många olika sätt att förhindra detta, men de är förmodligen alla relaterade till hur du generellt skulle rensa upp den här funktionen. Som det är skrivet nu startar du i princip två helt separata asynkrona kodvägar. Båda börjar med Post.find({})
och gå därifrån. De körs var och en parallellt och ingen av dem har någon aning om vad den andra kodvägen gör. Som sådan har du inget konkret sätt att skicka ett svar från en, men inte båda.
Så sättet att rensa upp detta är förmodligen att inte ha två helt separata asynkrona kodvägar. Du måste samordna dem på något sätt. I stort sett alla fall här kommer du att vilja byta över till löftesgränssnittet till din databas eftersom det kommer att ge dig mycket fler alternativ för att hantera ditt kontrollflöde. Till exempel, om du av prestandaskäl vill ha två parallella asynkrona operationer igång samtidigt, med löften, kan du använda Promise.all()
eller Promise.allSettled()
att övervaka båda och veta när de är klara och sedan, med båda resultaten i hand, bestämma vilket svar som ska skickas.
Eller, om du vill sekvensera dem, kan du använda async/await
för att ganska enkelt sekvensera de två operationerna och sedan när du gör en return
, kommer den faktiskt att återvända från toppnivåfunktionen och stoppar ytterligare kontrollflöde.
Om du vill hålla fast vid återuppringningsgränssnittet till din databas, måste du förmodligen kapsla den andra operationen i det första alternativet så att du inte startar den andra operationen om du ska göra res.send({ message: "No posts" })
.