怎么解决在vue3中watch不及时更新

解决方案 1:在 processChunk 函数中更新 questionList.value 后再更新 questionid.valuefirstsendId.value

通过调整 questionid.valuefirstsendId.value 更新的位置,我们可以确保它们的值在更新 questionList.value 之前就已经准备好:

const processChunk = (chunk: any) => {
  if (paused.value === true) {
    return;
  }

  const lines = chunk.split("\n").filter((line: any) => line.trim() !== "");
  const newContent = lines.join("").replace(/\r/g, "");

  const regex = /"data":"(.*?)"/g;
  let match;
  const results = [];
  while ((match = regex.exec(newContent)) !== null) {
    const cleanedData = match[1]
      .replace(/^\n{2}/, "")
      .replace(/\r/g, "")
      .replace(/\n/g, "");

    const parsedData = JSON.parse(`"${cleanedData}"`);
    results.push(parsedData);
  }

  const answerSessionList = [];

  const answerSessionRegex = /AnswerSessionRes\(id=(\d+), messageId=(\d+)\)/;
  const answerSessions = results.filter((data) => answerSessionRegex.test(data));
  console.log(results, "Results");
  console.log(answerSessions, "answerSessions");

  if (answerSessions.length > 0) {
    answerSessions.forEach((session) => {
      const matches = session.match(answerSessionRegex);
      console.log(matches);

      if (matches) {
        const sessionObject = {
          id: parseInt(matches[1], 10),
          messageId: BigInt(matches[2])
        };
        console.log(sessionObject);
        const serializedObj = JSON.stringify({
          ...sessionObject,
          messageId: sessionObject.messageId.toString() // Convert BigInt to string
        });
        answerSessionList.push(serializedObj);
      }
    });
    const jsonObject = JSON.parse(answerSessionList[0]);

    // 先更新 questionid 和 messageIds
    questionid.value = jsonObject.id;
    messageIds.value = jsonObject.messageId;
    firstsendId.value = jsonObject.messageId;
  }

  const filteredResults = results.filter((data) => !answerSessionRegex.test(data));

  const sentence = filteredResults.join("");
  
  // 然后再更新 questionList.value
  questionList.value = sentence;
};

解决方案 2:使用 nextTick

使用 Vue.nextTick 确保在更新了 questionid.valuefirstsendId.value 后,watch 函数可以在 DOM 更新后被调用。

processChunk 函数的最后,更新 questionList.value 时使用 nextTick

import { nextTick } from 'vue';

const processChunk = (chunk: any) => {
  if (paused.value === true) {
    return;
  }

  // 处理数据的逻辑...

  if (answerSessions.length > 0) {
    // 更新 questionid 和 firstsendId
    questionid.value = jsonObject.id;
    messageIds.value = jsonObject.messageId;
    firstsendId.value = jsonObject.messageId;
  }

  const filteredResults = results.filter((data) => !answerSessionRegex.test(data));
  const sentence = filteredResults.join("");

  // 使用 nextTick 确保在 DOM 更新后才更新 questionList.value
  nextTick(() => {
    questionList.value = sentence;
  });
};

解决方案 3:使用 await 确保顺序执行

确保所有的异步操作都已完成,可以在更新 questionList.value 之前使用 await 确保顺序执行。

例如:

const processChunk = async (chunk: any) => {
  if (paused.value === true) {
    return;
  }

  // 处理数据的逻辑...

  if (answerSessions.length > 0) {
    // 更新 questionid 和 firstsendId
    questionid.value = jsonObject.id;
    messageIds.value = jsonObject.messageId;
    firstsendId.value = jsonObject.messageId;
  }

  const filteredResults = results.filter((data) => !answerSessionRegex.test(data));
  const sentence = filteredResults.join("");

  // 更新 questionList.value
  await new Promise((resolve) => setTimeout(resolve, 0)); // 强制下一次事件循环
  questionList.value = sentence;
};

总结

通过确保在更新 questionList.value 之前 questionid.valuefirstsendId.value 已经更新,以上几种方法都可以解决你遇到的问题。选择适合你的代码逻辑的解决方案进行优化。

如果还不行的话......

解决方案 4:使用 watchEffect 代替 watch

watchEffect 会在依赖的响应式数据发生变化时立即执行,这样我们可以确保获取到最新的值。

import { watchEffect } from 'vue';

watchEffect(() => {
  if (questionList.value) {
    content.value[content.value.length - 1] = {
      loading: false,
      content: questionList.value,
      role: AI_ROLE,
      id: questionid.value,
      messageId: firstsendId.value,
    };
  }
});

解决方案 5:显式等待异步函数完成

ass 函数内等待 getSessionJHistorys 异步函数完成并明确设置 idmessageId。确保这些状态更新在下一个问题处理之前完成。

const ass = async (item: any) => {
  if (canSend.value) {
    canSend.value = false;
    if (item.clearFlag) {
      setTimeout(() => {
        question.value = "";
      }, 0);
    }
  } else {
    message.warn("请等待上一个问题回答完再提问");
    return;
  }

  ifhiddenText.value = false;
  paused.value = false;
  displayData.value = [];
  content.value.push({
    content: item.text || fileList.value[1].name,
    role: USER_ROLE,
  });

  setTimeout(async () => {
    content.value.push({
      loading: true,
      content: "内容生成中...",
      role: AI_ROLE,
    });

    document.getElementById("bottom")?.scrollIntoView?.();

    const formData = new FormData();
    const jsonObject = {
      rootTenantId: "151515",
      tenantId: "222",
      prompt: item.text || "",
      messageId: props.message ? props.message : firstsendId.value,
    };
    formData.append("messageRequest", JSON.stringify(jsonObject));
    formData.append("file", fileList.value[1] || []);

    // 等待 getSessionJHistorys 函数完成
    const res = await getSessionJHistorys(formData);

    // 确保 id 和 messageId 在此处已更新
    console.log(questionid.value, "Updated questionid.value");
    console.log(firstsendId.value, "Updated firstsendId.value");

    if (!props.message) {
      emit("onLoad");
    }
  }, 100);
};

解决方案 6:将状态更新移到回调函数内部

可以在 processChunk 函数内部明确地将状态更新放在 watch 之前。确保 idmessageId 的更新在 watch 触发之前完成。

const processChunk = (chunk: any) => {
  if (paused.value === true) {
    return;
  }

  // 数据处理逻辑...

  if (answerSessions.length > 0) {
    answerSessions.forEach((session) => {
      const matches = session.match(answerSessionRegex);
      if (matches) {
        const sessionObject = {
          id: parseInt(matches[1], 10),
          messageId: BigInt(matches[2])
        };
        const serializedObj = JSON.stringify({
          ...sessionObject,
          messageId: sessionObject.messageId.toString()
        });
        answerSessionList.push(serializedObj);
      }
    });

    const jsonObject = JSON.parse(answerSessionList[0]);

    // 确保 id 和 messageId 先更新
    questionid.value = jsonObject.id;
    messageIds.value = jsonObject.messageId;
    firstsendId.value = jsonObject.messageId;
  }

  const filteredResults = results.filter((data) => !answerSessionRegex.test(data));
  const sentence = filteredResults.join("");
  
  questionList.value = sentence;
};

总结

通过确保异步函数执行顺序和状态更新顺序,可以确保 watch 函数捕获到最新的数据变化。可以尝试将状态更新与异步操作分离,并确保状态更新完成后再触发 watch。此外,也可以考虑使用 watchEffect 作为替代方法。

你可能感兴趣的:(vue.js,javascript,前端)