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
相关产品推荐
相关产品推荐

