MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Perché ricevo Impossibile impostare le intestazioni dopo che sono state inviate all'errore del client in Nodejs?

Proprio qui:

Post.find({}, function(err, docs) {
    if (docs.length == 0)
        return res.send({ message: "No posts" });

Se raggiungi quella condizione di docs.length == 0 , quindi invierai una risposta alla richiesta. Ma il tuo return ritorna SOLO da Post.find() richiama. Non viene restituito dal tuo trendingposts() funzione.

Quindi, nel frattempo, quella funzione continua ad essere eseguita e alla fine arriva a questo codice:

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

Dove quindi invii un'altra risposta alla stessa richiesta. Questo è ciò che fa scattare l'errore Cannot set headers after they are sent to the client che vedi.

Esistono molti modi diversi per prevenirlo, ma probabilmente sono tutti correlati al modo in cui generalmente ripulire questa funzione. Nel modo in cui è scritto ora, essenzialmente inizi due percorsi di codice asincroni completamente separati. Entrambi iniziano con Post.find({}) e vai da lì. Ognuno di loro viene eseguito in parallelo e nessuno dei due ha idea di cosa stia facendo l'altro percorso del codice. In quanto tale, non hai un modo concreto per inviare una risposta da uno, ma non da entrambi.

Quindi, il modo per ripulire questo è probabilmente non avere due percorsi di codice asincroni completamente separati. Devi coordinarli in qualche modo. In quasi tutti i casi qui, vorrai passare all'interfaccia di promessa sul tuo database in quanto ciò ti darà molte più opzioni per la gestione del flusso di controllo. Ad esempio, se per motivi di prestazioni, desideri che due operazioni asincrone parallele vengano eseguite contemporaneamente, con promesse, puoi utilizzare Promise.all() o Promise.allSettled() per monitorare entrambi e sapere quando hanno finito e poi, con entrambi i risultati in mano, decidere quale risposta inviare.

Oppure, se vuoi metterli in sequenza, puoi usare async/await per mettere in sequenza abbastanza facilmente le due operazioni e poi quando fai un return , tornerà effettivamente dalla funzione di primo livello e interromperà l'ulteriore flusso di controllo.

Se vuoi mantenere l'interfaccia di callback sul tuo database, probabilmente dovrai annidare la seconda operazione nella prima opzione in modo da non avviare la seconda operazione se intendi fare res.send({ message: "No posts" }) .