多个嵌套的猫鼬承诺的结构

Structure of multiple nested Mongoose promises

我如何构造一个函数,其中有多个 Mongoose.findOne() 相互嵌套?

我需要做类似的事情

const userId  = '...';
const postId  = '...';
const imageId = '...';

User.findById(userId).then(user => {
  if (!user) {
    return res.status(400).json({
      status: 'error',
      err: 'User not found',
    });
  }

  Post.findById(postId).then(post => {
    if (!post) {
      return res.status(400).json({
        status: 'error',
        err: 'Post not found',
      });
    }

    Image.findById(imageId).then(image => {
      if (!image) {
        return res.status(400).json({
        status: 'error',
        err: 'Image not found',
      });

      // DO SOMETHING WITH VARIABLES 'user', 'post', AND 'image'

    }).catch(err => { .. });
  }).catch(err => { .. });
}).catch(err => { .. });

既然Collection.findById()returns一个promise,我想我应该使用链接而不是这个结构。

所以它可能类似于

User
  .findById(userId)
  .then(user => Post.findById(postId))
  .then(post => Image.findById(imageId))
  .then(image => {
      // DO SOMETHING WITH VARIABLES 'user', 'post', AND 'image'
  });
  .catch(err => { .. });

但我不知道如何访问变量 userpostimage,也不知道如何抛出错误,因此我可以在 catch声明。

编辑

我试过了

async function getPostAsync() {
  const userId = '597989c668189f31483ffdbf';
  const postId = '597989c62624ea74750c74f8';

  if (!userId) {
    throw new Error('User id missing');
  }

  if (!postId) {
    throw new Error('Post id missing');
  }

  const user = await User.findById(userId);
  const post = await Post.findById(postId);

  return post;
}

app.get('/', (req, res) => {
  getPostAsync().then(post => {
    res.json({
      status: 'success',
    });
  }).catch(err => {
    res.status(400).json({
      status: 'error',
      err
    });
  })
});

但我刚收到

{
  "status": "error",
  "err": {}
}

我是不是做错了什么?

但即使使用

我也得到相同的结果
async function getPostAsync() {
  throw new Error('msg');
  return Post.find();
}

所以我可能调用了错误的异步函数。

您无法在稍后的承诺中访问这些变量 then,但您可以通过将局部解析值分配给全局变量来绕过它

let globalUser, globalPost; // create variables for later

User
    .findById(userId)
    .then(user => {
        globalUser = user; // assign to global
        return Post.findById(postId)
    })
    .then(post => {
        globalPost = post; // assign to global
        return Image.findById(imageId)
    })
    .then(image => {
        // DO SOMETHING WITH VARIABLES 'globalUser', 'globalPost', AND 'image'
    })
    .catch(err => {... });

编辑:或使用async/await时:

async function() {
    const user = await User.findById(userId);
    const post = await Post.findById(postId);
    const image = await Image.findById(imageId);

    // do something with user, post and image
}

鉴于您的承诺不相互依赖,您也可以在异步函数中使用 Promise.all()

async function() {
    const result = await Promise.all([
        User.findById(userId),
        Post.findById(postId),
        Image.findById(imageId)
    ]);

    const [user, post, image] = result;

    // do something with user, post and image
}

编辑 2:错误处理

async function getImage() {
    let user;
    try {
        user = await User.findById(userId);
    } catch (error) { // deal with rejection of `User.findById`
        // do something with error
    }

    // if these fail the entire function will throw
    const post = await Post.findById(postId);
    const image = await Image.findById(imageId);

    return image;
}

getImage()
    .then(image => {... })
    .catch(error => {... }); // deal with rejection of `getImage` as a whole

以上代码展示了在异步函数中处理错误的方法。第一个是我们如何处理 User.findById 函数中的错误,只需将其包装在 try catch 块中即可。

第二种方法是简单地让整个异步函数抛出一个错误。 IE。如果 Post.findByIdImage.findById 承诺拒绝,整个 getImage() 承诺将拒绝,您可以在 .catch() 处理程序中处理。

您可以使用 Promise.all:

Promise.all([
    User.findById(userId),
    Post.findById(postId),
    Image.findById(imageId)
])
.then(result)=>{
    let user = result[0];
    let post = result[1];
    let image = result[2];
})
.catch(err => { .. });

destructing assignment:

Promise.all([
    User.findById(userId),
    Post.findById(postId),
    Image.findById(imageId)
])
.then(([user, post, image])=>{...})
.catch(err => { .. });