【问题标题】:What is the best way to use nested promises and await使用嵌套承诺和等待的最佳方式是什么
【发布时间】:2021-03-13 04:29:59
【问题描述】:

我想获取当前用户的所有帖子和他朋友的所有帖子。该代码正在运行,但我对同时使用 async-await 和 Promise.all 感到困惑。当我一起使用它们时应该如何处理错误以及使用嵌套异步函数的最佳方法是什么?提前致谢。

router.get("/timeline", verify, async(req, res, next) => {
  let postArray = [];
  try {
    const posts = await Post.find({
      userId: req.user.id
    });
    postArray.push(...posts);
    const currentUser = await User.findById(req.user.id);
    const promises = currentUser.friends.map(async(friendId) => {
      const posts = await Post.find({
        userId: friendId
      });
      posts.map((p) => postArray.push(p));
    });
    await Promise.all(promises).then(() => res.send(postArray));
  } catch (err) {
    next(err);
  }
});

verify 中间件由 JWT 验证器提供。我的模型是这样的:

const UserSchema = new mongoose.Schema(
  {
    username: {
      type: String,
      required: true,
      min: 3,
      max: 20,
      unique: true,
    },
    email: {
      type: String,
      required: true,
      max: 50,
      unique: true,
    },
    password: {
      type: String,
      required: true,
      min: 6,
      max: 1024,
    },
    profilePicture: {
      type: String,
      default: "",
    },
    coverPicture: {
      type: String,
      default: "",
    },
    isAdmin: {
      type: Boolean,
      default: false,
    },
    friends: {
      type: Array,
      default: [],
    },
  },
  { timestamps: true }
);
const PostSchema = new mongoose.Schema(
  {
    userId: {
      type: String,
      required: true,
    },
    desc: {
      type: String,
      max: 500
    },
    img: {
      type: String,
    },
    likes: {
      type: Array,
      default: [],
    },
  },
  { timestamps: true }
);

【问题讨论】:

    标签: javascript node.js mongoose


    【解决方案1】:

    这是我的简化版:

    router.get("/timeline", verify, async (req, res, next) => {
        try {
            const postArray = await Post.find({ userId: req.user.id });
            const currentUser = await User.findById(req.user.id);
            await Promise.all(currentUser.friends.map(friendId => {
                return Post.find({ userId: friendId }).then(fPosts => postArray.push(...fPosts));
            }));
            res.send(postArray);
        } catch (err) {
            next(err);
        }
    });
    

    变化:

    1. 只需使用第一位数据初始化postArray,而不是将其声明为空数组,然后从另一个数组推入。
    2. 不是每次都迭代posts,只需一次操作将它们全部推入postArray
    3. 我不喜欢在await 中使用async 回调和.map(),因为这意味着对于普通读者来说.map() 循环实际上会暂停await(它会不是)。所以,我只是使用.then() 将朋友帖子收集到postArray 并从Post.find() 返回承诺。

    我对同时使用 async-await 和 Promise.all 感到困惑

    当您有多个承诺并且想知道它们何时完成时,您可以使用Promise.all()。这可以与 async/await 一起使用就好了,因为它们也对 Promise 进行操作。在我的示例中,我在.map() 循环内执行return Post.find(),这意味着.map() 的返回将是一组promise,非常适合与Promise.all() 一起使用,以了解它们何时完成。

    一起使用错误应该如何处理

    如果您是 await Promise.all(),则错误处理就像您的所有其他 await 语句一样。错误将被您周围的try/catch 捕获。

    使用嵌套异步函数的最佳方式是什么

    这个问题真的没有唯一的答案。你有一种有效的方法。我提供了一个对我来说似乎更简单的细微变化。简单是旁观者的眼中。


    仅供参考,有些人不喜欢在同一个代码块中看到 .then()await - 希望您使用一个成语或另一个。我不归咎于那种黑白规则,但更喜欢使用对我来说似乎更简单的东西,偶尔会看到我将它们混合用于特定情况。

    如果您愿意,这里是上面代码的修改版本,没有.then()

    router.get("/timeline", verify, async (req, res, next) => {
        try {
            const postArray = await Post.find({ userId: req.user.id });
            const currentUser = await User.findById(req.user.id);
            await Promise.all(currentUser.friends.map(async friendId => {
                let fPosts = await Post.find({ userId: friendId });
                postArray.push(...fPosts);
            }));
            res.send(postArray);
        } catch (err) {
            next(err);
        }
    });
    

    【讨论】:

      【解决方案2】:

      jfriend00 的回答很棒。只需添加它,如果您想在您的 api 无法加载朋友的帖子时显示自定义错误,您可以这样做。

      router.get("/timeline", verify, async (req, res, next) => {
          try {
              const postArray = await Post.find({ userId: req.user.id });
              const currentUser = await User.findById(req.user.id);
              await Promise.all(currentUser.friends.map(async friendId => {
                  let fPosts = await Post.find({ userId: friendId });
                  postArray.push(...fPosts);
              })).catch((e) => {
                   throw new Error("Failed to load friend's post")    // notice a separate catch 
              })
              res.send(postArray);
          } catch (err) {
              next(err);
          }
      });
      

      【讨论】:

        猜你喜欢
        • 2020-04-21
        • 1970-01-01
        • 2018-05-05
        • 1970-01-01
        • 2017-04-04
        • 2019-04-29
        • 1970-01-01
        • 1970-01-01
        • 2018-04-17
        相关资源
        最近更新 更多