如何将 async/await 与多个相关集合一起使用



我正在尝试使用带有承诺和猫鼬引用的异步/等待来解决问题。

下面的代码几乎可以工作:创建了 3 个帖子,第一个帖子的评论也是如此,但第三个帖子的评论都没有创建

我假设这是因为我没有将异步/等待放在正确的位置,但我不知道如何组织代码以使其工作。

const seedData = [
{
title: 'Post 1',
content: `beard sustainable Odd Future pour-over Pitchfork DIY fanny pack art party`,
comments: [
{ content: 'comment1 1' },
{ content: 'comment1 2' },
{ content: 'comment1 3' }
]
},
{
title: 'Post 2',
content: `flannel gentrify organic deep v PBR chia Williamsburg ethical`,
comments: []
},
{
title: 'Post 3',
content: `bag normcore meggings hoodie polaroid gastropub fashion`,
comments: [{ content: 'comment3 1' }, { content: 'comment3 2' }]
}
];
async function createPostsAndComments() {
let promises = [];
// delete existing documents
Post.remove(() => {});
Comment.remove(() => {});
// create three posts along with their comments
seedData.forEach(async postData => {
// create the post
let post = new Post({
_id: new mongoose.Types.ObjectId(),
title: postData.title,
content: postData.content
});
// wait for the promise returned by `post.save`
promises.push(
post.save(error => {
if (error) console.log(error.message);
// create the comments of the current post
postData.comments.forEach(async commentData => {
const comment = new Comment({
content: commentData.content,
post: post._id
});
// wait for the promise from `comment.save`
promises.push(
comment.save(error => {
if (error) console.log(error.message);
})
);
});
})
);
});
return Promise.all(promises);
}
async function initSeed() {
mongoose.connect(process.env.DATABASE, { useMongoClient: true });
await createPostsAndComments();
mongoose.connection.close();
}
initSeed();

如果它有用,以下是架构:

import mongoose from 'mongoose';
exports.commentSchema = new mongoose.Schema(
{
content: {
type: String,
required: true
},
post: { type: mongoose.Schema.Types.ObjectId, ref: 'Post' }
},
{
toJSON: { virtuals: true }, // TODO: what's this?
toObject: { virtuals: true }
}
);
exports.Comment = mongoose.model('Comment', exports.commentSchema);

import mongoose from 'mongoose';
exports.postSchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
title: {
type: String,
required: true
},
content: {
type: String,
required: true
},
comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }]
});
exports.Post = mongoose.model('Post', exports.postSchema);

您需要实际await返回承诺的异步调用。就像.remove().save(),基本上是与数据库的每一次交互。我们还可以使用Promise.all()使一些事情更简单:

// <<-- You use async because there are "inner" awaits.
// Otherwise just return a promise
async function createPostsAndComments() {   
let promises = [];
// delete existing documents  <<-- This is actually async so "await"
await Promise.all([Post,Comment].map(m => m.remove()));
// create three posts along with their comments <<-- Not actually async
seedData.forEach(postData => {
// create the post
let post = new Post({
_id: new mongoose.Types.ObjectId(),
title: postData.title,
content: postData.content
});
// wait for the promise returned by `post.save`   <<-- You mixed a callback here
promises.push(post.save());
// create the comments of the current post  // <<-- Again, not async
postData.comments.forEach(commentData => {
const comment = new Comment({
content: commentData.content,
post: post._id
});
// <<-- Removing the callback again
promises.push(comment.save())
});
});
return Promise.all(promises);
}
// Just write a closure that wraps the program. async allows inner await
(async function()  {
try {
const conn = await mongoose.connect(process.env.DATABASE, { useMongoClient: true }); // <-- Yep it's a Promise
await createPostsAndComments();
} catch(e) {
console.error(e);
} finally {
mongoose.disconnect();
}
})();

或者,只需使.remove()调用也成为promises数组的一部分,现在不需要在该函数中进行async/await。反正只是承诺:

function createPostsAndComments() {   
let promises = [];
//await Promise.all([Post,Comment].map(m => m.remove()));
promises = [Post,Comment].map(m => m.remove());
// create three posts along with their comments <<-- Not actually async
seedData.forEach(postData => {
// create the post
let post = new Post({
_id: new mongoose.Types.ObjectId(),
title: postData.title,
content: postData.content
});
// wait for the promise returned by `post.save`   <<-- You mixed a callback here
promises.push(post.save());
// create the comments of the current post  // <<-- Again, not async
postData.comments.forEach(commentData => {
const comment = new Comment({
content: commentData.content,
post: post._id
});
// <<-- Removing the callback again
promises.push(comment.save())
});
});
return Promise.all(promises);
}

甚至只是await所有东西而不是喂Promise.all

async function createPostsAndComments() {   
await Promise.all([Post,Comment].map(m => m.remove()));
for( let postData of seedData ) {
// create the post
let post = new Post({
_id: new mongoose.Types.ObjectId(),
title: postData.title,
content: postData.content
});
await post.save());
for ( let commentData of postData.comments ) {
const comment = new Comment({
content: commentData.content,
post: post._id
});
await comment.save())
}
}
}

这些似乎是你缺少的概念。

基本上async是关键字,这意味着"内部块"将使用await。如果不使用await则无需将块标记为async

那么当然,任何"承诺"都需要一个await来代替任何.then().只是不要将回调与承诺混合使用。如果你真的需要,那么你可以将回调样式的返回包装在 Promise 中,但这里的代码不需要它们。

另一个主要考虑因素是"错误处理"。因此,我们需要做的就是使用async/await关键字实现try..catch如图所示。这比在 Promise 语法中.catch()更可取,并且基本上将从"内部"函数抛出的所有错误推迟到"外部"块并在那里报告错误。

因此,无需在createPostsAndComments()函数"内部"添加错误处理,因为该函数本身是在try..catch中调用的。

最新更新