为什么这个脚本在Javascript中延迟了?

时间:2016-03-20 14:53:29

标签: 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()

});
&#13;
<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>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:1)

您正在为每个对象调用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,您将获得更好的性能。您可以创建画布,在该画布上绘制圆弧,然后使用ctx.drawImage(canvasImage,...绘制该画布,以获得更快的更新。

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

<强>更新

随着浏览器世界的变化,我在这种情况下测试了forEach的使用,在这种情况下,新闻并不好。与forEachforwhile

相比,do while仍会在每次迭代时增加额外的额外开销

需要注意的重要事项(以及为什么我删除最后一段)是开销是每次迭代,如果你有少量的迭代和每次迭代的大量代码,那么开销是无关紧要的,不值得麻烦的个人编码风格应该选择在这些情况下使用什么样的风格。

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

这适用于Chrome,Edge和Firefox,它们都显示标准迭代(for循环),内联代码(不调用函数)是最快的,接下来比标准迭代慢10%是标准迭代函数调用(如forEach),然后forEach每次迭代超过2X的额外开销。 (每个测试使用15-20比1的代码余额,即迭代内的代码比迭代所需的最小代码长15-20倍。因此forforEach一行循环中循环和10-15行代码。)

如果你正在处理几千到几万的数组,那么差别就不值得烦恼了。如果你处理的是数千到数百万的加,你应该避免使用forEach

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

经过测试

  • Chrome版本50.0.2661.37 beta-m
  • Firefox 46.0b2
  • Edge 25.10586

答案 1 :(得分:0)

可能有所帮助的一些事情。

从for循环中取出objects.length并在开始循环之前将其分配给var。目前,您在循环的每次交互中计算对象的长度。

更好的是使用objects.forEach迭代数组。

最后为什么draw()会在两个for循环的底部调用自身?这将很快填满事件循环,并怀疑减速的主要原因。