You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript异步函数未正确等待:列表同时渲染问题求助

问题说明

原本在typeOutText完成打字效果后,应先执行fadeInSlide3List1并等待其完成,再执行fadeInSlide3List2。添加Enter/空格键加速事件前,两个列表能按顺序渲染,但现在两者同时出现,调试数小时未找到原因。

相关代码

async function fadeInSlide3List1() {
  const slide3List1 = slide3Lists[0];
  const container = document.querySelector(".design-list1");
  container.style.visibility = "hidden";

  let nextItemSpeed = 2000;

  for (let i = 0; i < slide3List1.length; i++) {
    const listItem = document.createElement("li");
    listItem.textContent = slide3List1[i];
    listItem.style.opacity = 0;
    listItem.style.transition = "opacity 1.5s";

    container.appendChild(listItem);
  }

  container.style.visibility = "visible";

  const fadeNextItem = async (index) => {
    if (index < slide3List1.length) {
      const listItem = container.children[index];
      await new Promise((resolve) => setTimeout(resolve, nextItemSpeed));
      listItem.style.opacity = 1;
      fadeNextItem(index + 1);
    } else {
      window.removeEventListener("keydown", handleKeyPress);
    }
  };

  const handleKeyPress = (event) => {
    const keyPressed = event.key;
    if (keyPressed === "Enter" || keyPressed === " ") {
      nextItemSpeed = 500;
      fadeNextItem(0);
    }
  };

  window.addEventListener("keydown", handleKeyPress);

  fadeNextItem(0);
}

async function fadeInSlide3List2() {
  const slide3List2 = slide3Lists[1];
  const container = document.querySelector(".design-list2");
  container.style.visibility = "hidden";

  let nextItemSpeed = 2000;

  for (let i = 0; i < slide3List2.length; i++) {
    const listItem = document.createElement("li");
    listItem.textContent = slide3List2[i];
    listItem.style.opacity = 0;
    listItem.style.transition = "opacity 1.5s";

    container.appendChild(listItem);
  }

  container.style.visibility = "visible";

  const fadeNextItem = async (index) => {
    if (index < slide3List2.length) {
      const listItem = container.children[index];
      await new Promise((resolve) => setTimeout(resolve, nextItemSpeed));
      listItem.style.opacity = 1;
      fadeNextItem(index + 1);
    } else {
      window.removeEventListener("keydown", handleKeyPress);
    }
  };

  const handleKeyPress = (event) => {
    const keyPressed = event.key;
    if (keyPressed === "Enter" || keyPressed === " ") {
      nextItemSpeed = 500;
      fadeNextItem(0);
    }
  };

  window.addEventListener("keydown", handleKeyPress);

  fadeNextItem(0);
}

async function typeOutSlide3() {
  const slide3Lines = slideLines[2];
  const content = slideContent[2];

  if (content) {
    slide3Container.innerHTML = content;
  } else {
    let nextLineSpeed = typingSpeed;
    let delay = 1500;

    const renderNextLine = async (i) => {
      const line = slide3Lines[i];
      await new Promise((resolve) => setTimeout(resolve, delay));
      await typeOutText(
        slide3Container,
        line.text,
        nextLineSpeed,
        line.elementType,
      );
    };

    const handleKeyPress = (event) => {
      const keyPressed = event.key;
      if (keyPressed === "Enter" || keyPressed === " ") {
        window.removeEventListener("keydown", handleKeyPress);
        nextLineSpeed = 10;
        delay = 500;
      }
    };

    window.addEventListener("keydown", handleKeyPress);

    for (let i = 0; i < slide3Lines.length; i++) {
      await renderNextLine(i);
    }

    slideContent[2] = slide3Container.innerHTML;
  }

  const paragraphs = slide3Container.getElementsByTagName("p");
  if (paragraphs.length >= 2) {
    paragraphs[1].classList.add("second-p");
  }

  await fadeInSlide3List1();
  await fadeInSlide3List2();
}
问题根源与修复方案

核心问题

fadeInSlide3List1和fadeInSlide3List2是异步函数,但内部调用fadeNextItem(0)时未使用await,导致函数执行完同步代码就直接返回,不会等待整个列表淡入流程完成。因此await fadeInSlide3List1()实际上没等第一个列表渲染完,就直接执行了fadeInSlide3List2(),造成两者同时渲染。

另外还有两个次要问题:

  • 递归调用fadeNextItem(index + 1)时未加await,会导致递归流程无法正确等待,还可能引发未处理Promise警告。
  • 按下Enter/空格时重复调用fadeNextItem(0),会触发多个递归流程同时执行,导致加速逻辑混乱。

修复步骤

  1. 等待递归流程完成:在fadeInSlide3List1和fadeInSlide3List2中,调用fadeNextItem(0)时添加await:
// 替换原代码中的 fadeNextItem(0);
await fadeNextItem(0);
  1. 递归调用时等待:在fadeNextItem的递归调用处添加await:
// 替换原代码中的 fadeNextItem(index + 1);
await fadeNextItem(index + 1);
  1. 优化键盘事件逻辑:避免重复触发递归,只需修改速度即可,当前递归会自动使用新速度:
const handleKeyPress = (event) => {
  const keyPressed = event.key;
  if ((keyPressed === "Enter" || keyPressed === " ") && nextItemSpeed !== 500) {
    nextItemSpeed = 500;
    // 无需重新调用fadeNextItem(0),现有递归会自动用新速度继续执行
  }
};

修改完成后,await fadeInSlide3List1()会真正等待第一个列表完全淡入,再执行第二个列表的渲染,恢复原本的顺序执行逻辑。

内容的提问来源于stack exchange,提问作者Matthew Ford

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 08:38:07