猿问

在 Node.js 中为 mongoDB 链接多个承诺函数

有一个要求,只有在找到产品和用户时才能添加评论。所以我编写了代码来实现这个场景。


User.findById(req.params.userId).exec()

        .then(response => {

            console.log("response", response);

            if (response) {

                return Product.findById(req.params.productId).exec();

            }

            else {

                return res.status(404).json({

                    message: 'User not found'

                })

            }

        })

        .then(response => {

            console.log("response", response);

            if (!response) {

                return res.status(404).json({

                    message: 'Product not found'

                })

            }


            const review = new Review({

                _id: mongoose.Types.ObjectId(),

                rev: req.body.rev,

                productId: req.params.productId,

                userId: req.params.userId

            });


            return review.save();


        })

        .then(response => {

            console.log("responseeeeeeee", response);

            res.status(201).json({

                response

            })

        })

        .catch(error => {

            console.log("error", error);

            res.status(500).json({

                error

            })

        })

这工作正常,但一旦产品或用户丢失,它就会发出警告:


(node:17276) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

    at ServerResponse.setHeader (_http_outgoing.js:470:11)

    at ServerResponse.header (D:\backup-learning\project-shop-always\node_modules\express\lib\response.js:771:10)

    at ServerResponse.send (D:\backup-learning\project-shop-always\node_modules\express\lib\response.js:170:12)

    at ServerResponse.json (D:\backup-learning\project-shop-always\node_modules\express\lib\response.js:267:15)

    at User.findById.exec.then.then.then.catch.error (D:\backup-learning\project-shop-always\api\controllers\review-controller.js:58:29)

    at process._tickCallback (internal/process/next_tick.js:68:7)


LEATH
浏览 145回答 1
1回答

浮云间

问题在于,res.status当您return res.status(/*...*/)从then回调中执行操作时,该链会继续使用作为履行值的返回值。您不能为此使用单个链。此外,由于您需要同时定位用户和产品,因此最好并行执行该操作。见评论:// *** Start both the product and user search in parallelPromise.all([    User.findById(req.params.userId).exec(),    Product.findById(req.params.productId).exec()]).then(([user, product]) => {    // *** Handle it if either isn't found    if (!user) {        res.status(404).json({            message: 'User not found'        });    } else if (!product) {        res.status(404).json({            message: 'Product not found'        });    } else {        // *** Both found, do the review        const review = new Review({            _id: mongoose.Types.ObjectId(),            rev: req.body.rev,            productId: req.params.productId,            userId: req.params.userId        });        // *** Return the result of the save operation        return review.save()        .then(response => {            console.log("responseeeeeeee", response);            res.status(201).json({                response            });        }    }    // *** Implicit return of `undefined` here fulfills the promise with `undefined`, which is fine}).catch(error => {    // *** An error occurred finding the user, the product, or saving the review    console.log("error", error);    res.status(500).json({        error    })});如果您在任何现代版本的 Node.js 中执行此操作,您可以使用async函数和await:// *** In an `async` functiontry {    const [user, product] = await Promise.all([        User.findById(req.params.userId).exec(),        Product.findById(req.params.productId).exec()    ]);    if (!user) {        res.status(404).json({            message: 'User not found'        });    } else if (!product) {        res.status(404).json({            message: 'Product not found'        });    } else {        // *** Both found, do the review        const review = new Review({            _id: mongoose.Types.ObjectId(),            rev: req.body.rev,            productId: req.params.productId,            userId: req.params.userId        });        const response = await review.save();        console.log("responseeeeeeee", response);        res.status(201).json({            response        });    }} catch (error) {    console.log("error", error);    res.status(500).json({        error    })}请注意,整个代码包装在一个try/ catch,所以async功能这是永远都不会拒绝(除非console.log或res.send在catch块中引发错误),这样就不会导致未处理拒绝警告,如果你只是让你Express端点处理程序async(而通常将async函数传递给不希望收到承诺的东西是一种反模式)。(如果您想有点偏执,请将catch块的内容包装在另一个try/ 中catch。)
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答