componentDidUpdate() {
    if (this.state.currentDirectory === Constant.EVENT_DISCUSSION_COMMENTS) {
      console.log("Did update", this.state.commentList[0].reply_by);
    }
  }

  handleGetDiscussionComments = async (e) => {
    const target = e.target;
    const discussionID = target.getAttribute("data-key");
    const currentDirectory = Constant.EVENT_DISCUSSION_COMMENTS;

    if (discussionID !== null) {
      const commentList = await CommentApi.getCommentBasedOndiscussion_id(
        discussionID
      );

      await commentList.map(async (comment) => {
        const username = await User.getUserName(comment["reply_by"]).then(
          console.log("then", comment.reply_by)
        );
        comment["reply_by"] = username;
        console.log("async", comment.reply_by);
      });

      console.log("before setState", commentList[0].reply_by);

      this.setState({
        commentList,
        selectedDiscussionID: discussionID,
        currentDirectory,
      });

      console.log("after setState");
    }
  };

Поэтому проблема в том, что даже если я поставлю await перед функцией commentList.map, она все равно выполнит приведенный ниже код, как я могу этого избежать?

Вывод :
затем 5f3207204450b32620449657
затем 5f3207204450b32620449657
перед setState 5f3207204450b32620449657
Сделал обновление 5f3207204450b32620449657
после setState
async DummyPerson

При возникновении этой проблемы мне не удалось показать имя пользователя на веб-странице, вместо этого он показывает ObjectId.

2
Newbie 2 Сен 2020 в 09:17

2 ответа

Лучший ответ

Учитывая, что вы используете map, вы можете дождаться массива обещаний, который вы получите с Promise.all на map:

await Promise.all(commentList.map(async (comment) => {
        const username = await User.getUserName(comment["reply_by"]).then(
          console.log("then", comment.reply_by)
        );
        comment["reply_by"] = username;
        console.log("async", comment.reply_by);
      }));
2
lanxion 2 Сен 2020 в 06:25

Вы можете рефакторировать вещи примерно так.

  • Огромный if был перевернут, чтобы быть скорейшим возвращением, чтобы уменьшить вложение
  • Ненужный .then() был удален из функции сопоставления имени пользователя комментария
  • Там был добавлен необходимый Promise.all().
handleGetDiscussionComments = async (e) => {
  const target = e.target;
  const discussionID = target.getAttribute("data-key");
  const currentDirectory = Constant.EVENT_DISCUSSION_COMMENTS;

  if (discussionID === null) {
    return;
  }
  const commentList = await CommentApi.getCommentBasedOndiscussion_id(discussionID);

  await Promise.all(
    commentList.map(async (comment) => {
      comment["reply_by"] = await User.getUserName(comment["reply_by"]);
    }),
  );

  this.setState({
    commentList,
    selectedDiscussionID: discussionID,
    currentDirectory,
  });

  console.log("after setState");
};

Улучшение

Чтобы уточнить (ранее) последний пункт, который у меня был:

Еще одним улучшением будет сбор набора идентификаторов пользователей, для которых требуется выборка имени пользователя, и выборка каждого имени пользователя только один раз.

// Construct a set of unique user IDs
const userIdSet = new Set(commentList.map((c) => c.reply_by));
// Fetch an array of pairs [userid, username]
const userIdPairs = await Promise.all(
  [...userIdSet].map(async (userId) => [
    userId,
    await User.getUserName(userId),
  ]),
);
// Create a mapping out of it
const userIdMap = Object.fromEntries(userIdPairs);
// Augment comment objects with `reply_by_name` from the map
commentList.forEach((c) => (c.reply_by_name = userIdMap[c.reply_by]));

Более того, вы, вероятно, можете кэшировать сопоставление идентификатора пользователя <-> имени пользователя на стороне клиента, поэтому при загрузке новых комментариев вы, вероятно, уже загрузили имя пользователя.

// a global variable (I know, usually not encouraged,
// but pragmatically should be fine,
// and can be refactored to something fancier later)
const knownUserNames = {};

// ...

async function handleGetDiscussionComments() {
  // Construct a set of unique user IDs
  const userIdSet = new Set(commentList.map((c) => c.reply_by));
  // Fetch an array of pairs [userid, username] unless we already know the result
  const userIdPairs = await Promise.all(
    [...userIdSet].map(async (userId) => [
      userId,
      knownUserNames[userId] || (await User.getUserName(userId)),
    ]),
  );
  // Create a mapping out of it
  const userIdMap = Object.fromEntries(userIdPairs);
  // Augment comment objects with `reply_by_name` from the map
  commentList.forEach(
    (c) => (c.reply_by_name = userIdMap[c.reply_by]),
  );
  // Update the global known username mapping with any new results
  Object.assign(knownUserNames, userIdMap);
}
1
AKX 2 Сен 2020 в 07:28