【问题标题】:Why does mongoose run asynchronously when creating and updating a document?为什么 mongoose 在创建和更新文档时会异步运行?
【发布时间】:2020-03-16 06:02:05
【问题描述】:

在以下函数中,创建 work 文档后,我保存了通过 multer 模块检索到的请求中的图像。保存 image 文档时,我尝试更新work 推送所有图片的_ids 文档。

但不知何故,如果你看看下面的代码并关注 console.log,第二个 console.log 将首先执行,尽管我在创建图像时使用了 .then。这也意味着我在最后几行代码中得到了一个过时的 work 文档。

文档说 Model.create() 返回一个 Promise,这意味着如果我使用 .then(),它应该同步运行(如果我没错的话)。但在我的函数中并非如此:

function addToDB(req, res, model) {
    let imagesToAdd = [];
    Works.create(model)
    .then(work => {
        req.files.forEach(image => {
            let path = image.path.split('').map(char => char === '\\' ? '/' : char).join('');
            let imageObj = {
                fileName: image.filename,
                mimeType: image.mimetype,
                imageURL: `${req.baseURL}/${path}`,
                workId: work._id
            };

            imagesToAdd.push(imageObj);
        });

        Images.create(imagesToAdd)
        .then(createdImages => {
            let imageIds = [];
            createdImages.forEach(image => {
                console.log(image._id);
                imageIds.push(image._id);
            });
            Works.updateMany({_id: work._id}, {$push: {images: {$each: imageIds}}}).catch(err => handleError(err));
        })
        .catch(err => handleError(err));
        console.log('>'+work._id);
        return work._id;
    })
    .then(workId => {
        Works.findById(workId)
        .then(foundWork => {
            res.json(foundWork);
        })
        .catch(err => handleError(err));
    })
    .catch(err => handleError(err));
}

这是发布作品文档后的控制台:

执行后的cmd:

还有回应:

执行后的响应:

添加了 2 张图片。上面您在响应中看到 images 数组没有任何元素,而在 mongo 中保存了图片 ID:

执行后保存的工作:

最终目标是用新创建的 work 进行响应,其中包含图像 id,因此我可以进一步填充 work 的 images 数组 文档和 image 文档中的 workId

如何让代码同步运行?

【问题讨论】:

  • 第二个 console.log 在 Images.create(imagesToAdd) 承诺链之外,因此不会等待执行
  • if I'm not mistaken - 你错了 - 异步代码异步运行 - 总是 - “.then” 链将按顺序执行 - 但如前所述,第二个 console.log 不在 .create 链中
  • 您可能想要return Images.create...return Works.updateMany(.... - 将第二个console.log 放入随后的.then

标签: javascript mongoose es6-promise multer synchronous


【解决方案1】:

问题是这样的:

Images.create(imagesToAdd)
    .then(createdImages => {
        let imageIds = [];
        createdImages.forEach(image => {
            console.log(image._id);
            imageIds.push(image._id);
        });
        Works.updateMany({_id: work._id}, {$push: {images: {$each: imageIds}}}).catch(err => handleError(err));
    })

设置为异步运行,那么这个:

console.log('>'+work._id);
return work._id;

被执行,你转到下一个then,一段时间后返回第一个promise的结果。

正确的方法是:

 function addToDB(req, res, model) {
let imagesToAdd = [];
Works.create(model)
.then(work => {
    // Populate imagesToAdd
    req.files.forEach(image => {
        let path = image.path.split('').map(char => char === '\\' ? '/' : char).join('');
        let imageObj = {
            fileName: image.filename,
            mimeType: image.mimetype,
            imageURL: `${req.baseURL}/${path}`,
            workId: work._id
        };
        imagesToAdd.push(imageObj);
    });

    Images.create(imagesToAdd)
    .then(createdImages => {
        // images have been created
        let imageIds = [];
        createdImages.forEach(image => {
            console.log(image._id);
            imageIds.push(image._id);
        });
        // imageIds has been populated
        Works.updateMany({_id: work._id}, {$push: {images: {$each: imageIds}}})
        .then(() => {
            // After update is finished, findById
            Works.findById( work._id )
                .then( foundWork => {
                    // Return the work after it has been updated with images
                    res.json( foundWork );
                } )
                .catch( err => handleError( err ) );
        })
        .catch(err => handleError(err));
    })
    .catch(err => handleError(err));
})
.catch(err => handleError(err));                }

更简单的方法是使用 async / await。

【讨论】:

  • 我同意,但我不同意将 Works.findById( work._id ) 嵌套得更深 - 你可以使用 return Images.createreturn Works.updateMany 并避免不必要的嵌套 - 或者,正如你所说,使用异步/等待完美平坦的代码:p - 你真的不需要所有这些 .catch - 如果你编写正确的代码就可以了
  • 没错,我发现嵌套的承诺链无论如何都令人困惑
  • 然而,在这种情况下,当不使用 async/await 时,两级嵌套(因为 work 值)可能比替代方案更容易:p
  • 谢谢@PJohnson 和 JaromandaX。将研究使用 async/await。如果有人感兴趣,已经找到了一篇关于此的文章:codepedia.org/ama/…
猜你喜欢
  • 2016-01-13
  • 1970-01-01
  • 1970-01-01
  • 2017-09-24
  • 1970-01-01
  • 1970-01-01
  • 2019-10-05
  • 1970-01-01
  • 2017-03-17
相关资源
最近更新 更多