为什么画布绘制是异步的,但API是同步的?

时间:2019-06-11 08:56:06

标签: javascript asynchronous canvas browser

我正在编写神经网络的虚拟化,我想在每次训练迭代中重绘它,所以我有带有onclick回调的下一个按钮:

startButton.onclick = () => {
  for (let i = 0; i < trainData.length; i++) {
    setTimeout(() => {
      network.trainSample(trainData[i])
      ctx.clearRect(0, 0, width, height)
      drawNN(network)
    }, 0)
  }
}

问题是,如果我起飞setTimeout,它将执行所有训练,最后重绘所有内容。

据我所知,有一个事件循环和setTimeout的窍门是什么,它在事件队列中创建了一个Job,该任务将现在不准确地执行,但要尽快执行

好的,但是如果画布绘制是异步的,并且绘制延期到最后,为什么它的api是同步的?

最小示例:

const canv = document.getElementById('myCanv')
const ctx = canv.getContext('2d')

ctx.strokeStyle = '#000000'

for (let x = 0; x <= 100; x++) {
  ctx.clearRect(0, 0, 100, 100)
  ctx.beginPath()
  ctx.moveTo(0, 0)
  ctx.lineTo(x, 100)
  ctx.stroke()
}
<!DOCTYPE html>
<html>

<head>
</head>

<body>
  <canvas width="100" height="100" id="myCanv"></canvas>
</body>

</html>

1 个答案:

答案 0 :(得分:1)

您的用法是不正确的,即使画布绘制是同步的,您也很可能只看到最后一帧,并且它们之间有些奇怪的动画。您需要的是代替标准循环,而是使用某种动画循环。例如:

let i = 0;
function animationLoop() {
  if (i < trainData.length) {
     network.trainSample(trainData[i]);
     ctx.clearRect(0, 0, width, height);
     drawNN(network);
     i++;
     requestAnimationFrame(animationLoop);
  }
}
requestAnimationFrame(animationLoop);

在这里,我正在使用requestAnimationFrame,它将导致每秒大约60帧。我对您的情况的猜测可能仍然太快。您可以在setTimeout函数中使用附加的animateLoop来限制每秒的帧数。