javascript - 为什么这个脚本在 Javascript 中会出现延迟?

标签 javascript html canvas

我制作了一个脚本,其中应该有实时吸引彼此的小球。问题是速度非常慢。我使用了动画帧,所以我认为它应该更新每一帧,但事实并非如此。这是代码:

$(function() {

  var mouseDown
  var c = document.getElementById('myCanvas');
  var ctx = c.getContext("2d");
  var objects = []

  c.addEventListener("mousedown", onMouseDown);
  c.addEventListener("mouseup", onMouseUp);

  function createSquare(x, y, size, direction, xVel, yVel) {
    this.x = x;
    this.y = y;
    this.size = size;
    this.drawStylus = drawStylus;
  };

  function drawStylus() {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
    ctx.fill();
  };

  function getDistance(x1, y1, x2, y2) {
    return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
  }

  function draw() {
    ctx.clearRect(0, 0, 5000, 5000);
    for (i = 0; i < objects.length; i++) {

      var x = objects[i][0]
      var y = objects[i][1]
      var size = objects[i][2]
      var dir = Math.random() * Math.PI * 2
      var force = 0
      var xVel = 0
      var yVel = 0
      for (n = 0; n < objects.length; n++) {
        if (n != i) {
          force = 100 * objects[n][2] / getDistance(x, y, objects[n][0], objects[n][1])
          angle = Math.atan2(y - objects[n][1], x - objects[n][0])
          xVel += force * -Math.cos(angle)
          yVel += force * -Math.sin(angle)
          window.requestAnimationFrame(draw)
        };
      };

      ctx.beginPath();
      ctx.arc(x + xVel, y + yVel, size, 0, 2 * Math.PI);
      ctx.fill();
    };
  };

  function onMouseDown() {
    mouseDown = true
    x = event.clientX
    y = event.clientY
    size = 100

    animation = function() {
      size = size + 20

      var cursorSquare = new createSquare(x, y, size);
      cursorSquare.drawStylus();
      anim = window.requestAnimationFrame(animation)
    };
    window.requestAnimationFrame(animation)
  };

  function onMouseUp() {
    if (mouseDown) {
      window.cancelAnimationFrame(anim)
      var newSquare = new createSquare(x, y, size);
      objects.push([x, y, size])
      mouseDown = false
    };
  };

  function loop() {
    draw();
    window.requestAnimationFrame(loop);
  };

  function init() {
    loop();
  };

  init()

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<canvas id='myCanvas' width="5000" height="5000" style="border:1px solid #000000;"></canvas>

最佳答案

您正在为每个对象调用 requestAnimationFrame,这是使用 requestAnimationFrame (RAF) 的错误方法。

每帧只能调用一次,而不是每个对象调用一次。

function mainLoop(time){ // main loop RAF will add the time in milliseconds to the arguments.
    ctx.clearRect(0,0,canvas.width,canvas.height); // clear
    draw(); // call the draw loop
    requestAnimationFrame(loop); // request next frame
}
requestAnimationFrame(loop); // request next frame

使用绘图函数,如 ctx.arc非常慢。如果改为渲染图像,您将获得更好的性能ctx.drawImage 。您可以创建一个 Canvas ,在该 Canvas 上绘制圆弧,然后使用 ctx.drawImage(canvasImage,... 绘制该 Canvas 。以获得更快的更新。

另一个答案建议您使用 forEach ,不要使用forEach或任何涉及回调的数组函数,因为它们比使用标准循环(for、while、do)慢得多

更新

随着浏览器世界中事物的快速变化,我已经测试了 forEach 在这种情况下的使用,但在这种情况下,消息并不好。 forEachfor 相比,每次迭代仍然会增加显着的额外开销, while ,和do while

需要注意的重要一点(以及为什么我删除了最后一段)是每次迭代的开销,如果迭代次数很少并且每次迭代的代码量很大,那么开销是微不足道的,不值得麻烦的是,个人编码风格应该选择在这些情况下使用什么风格。

如果另一方面,您有大量迭代并且每次迭代处理量很小,那么使用 forEach 将显着影响循环的性能。

这对于 Chrome、Edge 和 Firefox 来说都是如此,所有这些都显示带有内联代码(不调用函数)的标准迭代(for 循环)是最快的,其次是带有 a 的标准迭代,比标准迭代慢 10%函数调用(如 forEach),然后是 forEach,每次迭代的额外开销超过 2 倍。 (每个测试都使用 15-20 比 1 的代码平衡,即迭代内的代码比迭代所需的最小代码长 15-20 倍。所以一行用于 forforEach 循环和 10-循环内有 15 行代码。)

如果您正在处理数千到数万的数组,则不值得担心差异,如果您正在处理数千到数百万的数组,则应该避免 forEach .

注意:我没有测试forEach在类型化数组上,因为这在这种情况下不适用。

测试于

  • Chrome 版本 50.0.2661.37 beta-m
  • 火狐46.0b2
  • 边缘25.10586

关于javascript - 为什么这个脚本在 Javascript 中会出现延迟?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36115240/

相关文章:

javascript - 为什么JS的日期会这样呢?

javascript - 经常更新 div 的内容

javascript - 循环更改 Rect html Canvas 的颜色

javascript - 我如何将 a 标签链接到 onload 模态窗口?

javascript - 我如何像 lodash 一样使用 JSDoc 对参数进行分组?

javascript - 我想在命令行上获取我的 linux 设备的准确经纬度。就像 HTML5 中的地理定位。我无权访问浏览器

java - JSP 文件输出 If/Else 问题

python - 如何在 Kivy 中将 Canvas 分配给多个小部件

javascript - 使 Firefox 渲染 Canvas 文本与 CSS 文本相同

javascript - 使用 Superagent 通过 ajax 提交包含图像值的表单