为什么这个脚本在Javascript中滞后? [英] Why does this script lag delay in Javascript?

查看:135
本文介绍了为什么这个脚本在Javascript中滞后?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我制作了一个脚本,其中应该有小球实时吸引彼此。问题是极其慢。我使用动画帧,所以我认为应该更新每一帧,但它不是。以下是代码:



  $(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  

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



>

  function mainLoop(time){// main loop RAF will将时间以毫秒为单位添加到参数。 
ctx.clearRect(0,0,canvas.width,canvas.height); // clear
draw(); //调用绘制循环
requestAnimationFrame(loop); // request next frame
}
requestAnimationFrame(loop); //请求下一个框架

使用 ctx.arc 很慢。如果你渲染图像,你将获得更好的性能 ctx.drawImage 。您可以创建一个画布,在该画布上绘制圆弧,然后使用 ctx.drawImage(canvasImage,... )绘制该画布以获得更快的更新。



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



strong> UPDATE



随着浏览器世界的变化,我在这种情况下测试了forEach的使用,在这种情况下,消息不好。 for ,, c> code>和 do while



重要的是要注意段落)是开销是每次迭代,如果你有少量的迭代和每次迭代大量的代码,那么开销是微不足道的,不值得麻烦,个人编码风格应该选择使用什么样式这些情况。



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



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



一个几千到几万的数组的区别是不值得麻烦的,如果你处理几十万到数百万加你应该避免 forEach



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



测试于




  • Chrome版本50.0.2661.37 beta-m

  • Firefox 46.0b2

  • Edge 25.10586


I've made a script where there are supposed to be little balls that attract eachother in real time. The problem it is EXTREMELY slow. I used animation frame, so I think it should be updating every frame, but it isn't. Here is the code:

$(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>

解决方案

You are calling requestAnimationFrame for each object, this is the wrong way to use requestAnimationFrame (RAF).

You should only call it once per frame not once per object.

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

Using the draw functions like ctx.arc is very slow. You will get much better performance if you render images instead ctx.drawImage. You can create a canvas, draw the arc on that canvas and then draw that canvas with ctx.drawImage(canvasImage,... to get a much faster update.

The other answer advised you to use forEach, don't use forEach or any of the array functions that involve callbacks as they are MUCH slower than using standard loops (for, while, do)

UPDATE

As things change rapidly in the browser world I have tested the use of forEach in this case and in this case the news is not good. forEach still adds a significant additional overhead on each iteration when compared to for, while , and do while

The important thing to note (and why I striked out the last paragraph) is that the overhead is per iteration, if you have a small number of iterations and a large amount of code per iteration then the overhead is insignificant and not worth the bother, personal coding style should make the choice of what style to use in those cases.

If on the other hand you have a large number of iterations and a small amount of processing per iteration then using forEach will significantly impact the performance of the loop.

This holds true for Chrome, Edge, and Firefox with all showing the standard iteration (for loops) with inline code (not calling a function) to be the quickest, next and 10% slower than standard iteration is standard iteration with a function call (like forEach), and then forEach with an additional overhead per iteration of over 2X. (each test used a 15-20 to 1 code balance, that is the code inside the iteration is 15-20 times longer than the minimum code required to iterate. So one line for the for, forEach loop and 10-15 lines of code inside the loop.)

If you are handling an array of a few thousand to tens of thousands the difference is not worth bothering with, If you are handling 100s of thousands to millions plus you should avoid forEach.

Note: I did not test forEach on typed arrays as that is not applicable in this case.

Tested on

  • Chrome Version 50.0.2661.37 beta-m
  • Firefox 46.0b2
  • Edge 25.10586

这篇关于为什么这个脚本在Javascript中滞后?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆