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

Canvas是否仅在<script>结束时刷新?如何在循环中强制刷新?

问题原因与解决方案

为什么你的代码看不到中间的绘制结果?

你写的wait函数用了同步的while循环,直接阻塞了JavaScript的主线程。浏览器的JS执行和页面渲染共用同一个主线程,当主线程被这个循环卡住时,浏览器根本没法处理渲染队列里的更新请求,所以你只能等到整个for循环跑完,才会看到最后一次的绘制结果。

正确的实现方式

方法1:用setTimeout实现异步间隔绘制

把原来的同步循环改成递归调用的异步逻辑,让浏览器有时间在两次绘制之间完成渲染:

let canvas = document.querySelector("canvas");
let context = canvas.getContext("2d");
let drawTimes = 0; // 记录已绘制次数

function drawGrid() {
  // 1. 清屏
  context.clearRect(0, 0, canvas.width, canvas.height);
  
  // 2. 绘制5x5矩形网格
  for (let i = 0; i < 5; i++) {
    // 修正原代码:j未声明为局部变量的问题
    for (let j = 0; j < 5; j++) {
      const width_custom = 60;
      const height_custom = 60;
      const gap = 20;
      const x = 100 + (width_custom + gap) * i;
      const y = 100 + (height_custom + gap) * j;

      // 绘制外层矩形
      context.beginPath();
      context.rect(x, y, width_custom, height_custom);
      context.stroke();
      
      // 50%概率绘制内层矩形
      if (Math.random() > 0.5) {
        context.beginPath();
        context.rect(x + 8, y + 8, width_custom - 16, height_custom - 16);
        context.stroke();
      }
    }
  }

  drawTimes++;
  // 未完成3次绘制则1秒后执行下一次
  if (drawTimes < 3) {
    setTimeout(drawGrid, 1000);
  }
}

// 启动第一次绘制
drawGrid();

方法2:用requestAnimationFrame实现更流畅的动画(推荐)

requestAnimationFrame会和浏览器的渲染帧同步执行,避免掉帧,适合需要连续动画的场景:

let canvas = document.querySelector("canvas");
let context = canvas.getContext("2d");
let drawTimes = 0;
let lastDrawTime = 0;

function animate(timestamp) {
  // 初始化第一次绘制的时间
  if (!lastDrawTime) lastDrawTime = timestamp;

  // 检查是否已过1秒
  if (timestamp - lastDrawTime >= 1000) {
    // 清屏并绘制网格
    context.clearRect(0, 0, canvas.width, canvas.height);
    for (let i = 0; i < 5; i++) {
      for (let j = 0; j < 5; j++) {
        const width_custom = 60;
        const height_custom = 60;
        const gap = 20;
        const x = 100 + (width_custom + gap) * i;
        const y = 100 + (height_custom + gap) * j;

        context.beginPath();
        context.rect(x, y, width_custom, height_custom);
        context.stroke();
        
        if (Math.random() > 0.5) {
          context.beginPath();
          context.rect(x + 8, y + 8, width_custom - 16, height_custom - 16);
          context.stroke();
        }
      }
    }

    lastDrawTime = timestamp;
    drawTimes++;
  }

  // 未完成3次绘制则继续
  if (drawTimes < 3) {
    requestAnimationFrame(animate);
  }
}

// 启动动画
requestAnimationFrame(animate);

关键知识点

  • 浏览器主线程是单线程的,JS执行和页面渲染无法同时进行,同步阻塞的代码会直接导致渲染延迟。
  • 异步API(setTimeout、requestAnimationFrame)会把回调放到事件队列,等主线程空闲时再执行,这样浏览器才有时间完成渲染更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 23:24:56