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

使用document.getElementById()时循环操作异常,问题出在哪里?

问题:表格行无法逐行延迟显示,仅在循环结束后一次性出现

脚本任务

  • 生成维度由表单数据决定的数字数组,由send_n()函数负责;
  • 在页面显示两列表格:数组元素与当前数组正元素的累加和;
  • 在表格末尾用一行两列输出正元素的最终总和;
  • 表格每行需延迟1秒出现,自定义了timeout(ms)函数实现,认为setTimeout异步会导致calculation_x函数异常。

问题现象

触发循环时控制台输出符合预期,但表格仅在循环结束后才一次性显示所有行。

尝试过的方法

曾使用setTimeout()和setInterval(),但未得到理想结果。

代码

JavaScript

function timeout(ms) {
  let date = new Date();
  while ((new Date()) - date <= ms) {
    // w/o do
  }
}

function calculation_x(arr, count) {
  let i = 0;
  let sum = 0;
  let table = String(`<table border="1px"><thead><tr><td>Элемент массива</td><td>Сумма положительных элементов массива</td></tr></thead><tbody id="result"></tbody></table>`);
  document.getElementById(`table-div`).innerHTML = table;
  for (i = 0; i < count; i++) {
    if (arr[i] > 0) {
      sum += arr[i];
    }
    table = `<tr><td>X[${i}] = ${arr[i]}</td><td>${sum}</td></tr>`;
    document.getElementById(`result`).innerHTML += table;
    console.log(`X[${i}] = ${arr[i]} | ${sum}`);
    timeout(1000);
  }
  timeout(1000);
  let result = `<tr><td colspan="2">Результат: ${sum}</td></tr>`;
  document.getElementById(`result`).innerHTML += result;
  console.log(`Сумма положительных элементов: ${sum}`);
}

function send_n() {
  let i = 0;
  let n = Number(document.getElementById(`n`).value);
  let numbers = new Array(n);
  for (i = 0; i < n; i++) {
    numbers[i] = Number(Math.floor(Math.random() * 200) - 100);
  }
  calculation_x(numbers, n);
}

HTML

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>

<body>
  <form>
    <input type="text" id="n" placeholder="Количество элементов массива">
    <input type="button" value="Принять" onclick="send_n()">
  </form>
  <div id="table-div"></div>
  <script src="/scripts.js"></script>
</body>

</html>

问题原因

你自定义的timeout函数是同步阻塞实现,通过while循环持续占用JS主线程。而浏览器的UI渲染与JS执行共享同一主线程,同步阻塞会导致所有DOM更新操作被积压,直到整个循环结束后才会一次性渲染,因此表格行无法逐行显示。

解决方案

使用Promise封装的异步延迟函数配合async/await,既不会阻塞主线程,又能保证每行按顺序延迟1秒出现。修改后的代码如下:

修改后的JavaScript代码

// 改用Promise封装的异步延迟函数
function timeout(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// 将calculation_x改为async函数,使用await实现顺序延迟
async function calculation_x(arr, count) {
  let sum = 0;
  const table = `<table border="1px"><thead><tr><td>数组元素</td><td>正元素累加和</td></tr></thead><tbody id="result"></tbody></table>`;
  document.getElementById(`table-div`).innerHTML = table;
  const resultTbody = document.getElementById(`result`);

  for (let i = 0; i < count; i++) {
    if (arr[i] > 0) {
      sum += arr[i];
    }
    const row = `<tr><td>X[${i}] = ${arr[i]}</td><td>${sum}</td></tr>`;
    resultTbody.innerHTML += row;
    console.log(`X[${i}] = ${arr[i]} | ${sum}`);
    // 等待1秒,此时浏览器可正常渲染DOM
    await timeout(1000);
  }

  await timeout(1000);
  const finalRow = `<tr><td colspan="2">最终结果: ${sum}</td></tr>`;
  resultTbody.innerHTML += finalRow;
  console.log(`正元素总和: ${sum}`);
}

function send_n() {
  const n = Number(document.getElementById(`n`).value);
  const numbers = Array.from({ length: n }, () => Math.floor(Math.random() * 200) - 100);
  calculation_x(numbers, n);
}

修改说明

  1. 异步延迟函数:将同步阻塞的timeout改为返回Promise的异步函数,配合await实现非阻塞延迟。
  2. async函数标记:给calculation_x添加async标记,允许在循环内使用await,保证每行渲染后等待1秒再执行下一步。
  3. DOM缓存:提前获取result tbody元素,避免循环内重复查询DOM,提升性能。
  4. 简化数组生成:用Array.from简化随机数组生成逻辑,功能不变。

修改后,表格行会每隔1秒逐行渲染到页面,控制台输出同步显示,最终总和行也会在最后一行显示1秒后出现。

内容的提问来源于stack exchange,提问作者Ivanov Vladislav

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 15:57:04