비동기 문제 배열 빈 nodejs 몽구스

Oct 19 2020

나는 req.body에 들어있는 ID 배열에서 각 제품의 이름과 가격을 얻고 새로운 모델 (결제)에 저장하고 싶습니다.이를 위해 각 제품을 살펴보고 ID를 찾습니다. db (Product.findById) 및 필요한 (이름 및 가격)을 arrayProducts에 개체로 저장하지만 arrayProducts가 채워지기 전에 newPayment가 생성되고 newPayment가 생성되도록 할 수 있으므로 비어 있습니다. forEach 제품 완료 후?

router.post('/new/payment', async (req, res) => {

    const date = Date.now();

    const { amount, clientId, products, services, officeId } = req.body;

    var arrayProducts = [];

    products.forEach(function (product) {
        var productFound = {};

        Product.findById(product, function (err, result) {
            if (err) {
                res.status(404).send({ error: "Oh uh, something went wrong", err: err });
            }
            else {
                productFound = { name: result.name, price: result.price };
                arrayProducts.push(productFound);
                console.log(arrayProducts);
            }
        })
    });
    console.log(arrayProducts);

    const newPayment = new Payment({ amount, clientId, products: arrayProducts, services, officeId, date });
    await newPayment.save((err) => {
        if (err) {
            res.status(404).send({ error: "Oh uh, something went wrong", err: err });
        }
        else {
            res.status(201).send({ status: "Payment successful", id: newPayment._id });
        }

    });;
});

답변

jfriend00 Oct 20 2020 at 03:12

node.js의 비 차단 비동기 작업에 대해 읽어야합니다. 귀하 Product.findById()는 비 블로킹 및 비동기식이므로 전체 경로 처리기가 실행을 마친 후 console.log(arrayProducts);그리고 그 이후에 오는 모든 코드 이후에 콜백이 LONG이라고 부릅니다 .

데이터베이스에서 N 개의 요청을하고 싶고 모든 요청이 언제 완료되었는지 알고 싶기 때문에 가장 효율적인 방법은 데이터베이스에 Promise 인터페이스를 사용하고 모든 DB 작업에서 일련의 promise를 수집하는 것입니다. 그런 다음 Promise.all()모든 작업이 완료되었음을 알리는 데 사용 합니다.

이것이 내가 제안하는 것입니다.

router.post('/new/payment', async (req, res) => {

    const date = Date.now();
    const { amount, clientId, products, services, officeId } = req.body;
    try {
        const allProducts = await Promise.all(products.map(async (product) => {
            const item = await Product.findById(product);
            return {name: item.name, price: item.price};
        }));
        const newPayment = new Payment({ amount, clientId, products: allProducts, services, officeId, date });
        await newPayment.save();
        res.status(201).send({ status: "Payment successful", id: newPayment._id });
    } catch(err) {
        res.status(404).send({ error: "Oh uh, something went wrong", err: err });
    }
});

이 코드에서 누락 된 다른 사항은 다음과 같습니다.

  1. 입력 값의 유효성을 검사 amount, clientId, products, services, officeId하고 누락되거나 유효하지 않은 경우 적절한 오류를 보냅니다.
  2. 데이터베이스에없는 제품이 지정된 경우 어떻게해야합니까?
  3. 데이터베이스 오류 (아마 500 오류 일 수 있음)가 발생하는 경우 404 오류가 적절하지 않을 수 있습니다.