2016-03-20 17 views
0

我已經寫了一個腳本,應該是有小球可以實時吸引彼此。問題極其緩慢。我使用動畫幀,所以我認爲它應該更新每一幀,但它不是。下面是代碼:爲什麼這個腳本在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 < 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>

+0

您明確一個5000 * 5000區域的每一幀,這將是真的很慢 –

+0

我只用700 * 700試過,它仍然存在相同的問題:( –

+0

你正在創建很多全局變量,不知道它是否對你的代碼有任何影響,但是我先把它清理乾淨。 –

回答

0

一對夫婦的事情,可能的幫助。

將objects.length移出for循環並在啓動循環之前將其分配給var。目前,您可以計算循環的每次交互中對象的長度。

更好的是使用objects.forEach遍歷數組。

最後爲什麼draw()自己在兩個for循環的底部?這將很快填滿事件循環,並懷疑減速的主要原因。

+0

當您訪問Array上的'.length'時,JS不會計算對象,而'.forEach()'更可能比'for'循環慢。 –

+0

謝謝,這解決了碰撞問題,但粒子仍然不能實時移動...我做錯了什麼? –

+0

@OwM你有巨大的粒子,填滿一個很大的空間,特別是如果它是一個圓圈,花費很多時間 –

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或任何涉及回調,因爲它們比使用標準循環更慢的陣列功能(同時,做)

UPDATE

由於事情在瀏覽器世界中迅速變化,我在這種情況下測試了forEach的使用情況,在這種情況下,新聞並不好。比較時forEach還增加了在每個迭代一個顯著的額外開銷forwhiledo while

需要注意的重要一點(爲什麼我刪除線了最後一段)是開銷是每個迭代的,如果你有一個少量的迭代和每次迭代大量的代碼,那麼開銷是微不足道的,不值得費心,個人編碼風格應該選擇在這些情況下使用什麼風格。

如果另一方面每次迭代都有大量迭代和少量處理,那麼使用forEach將顯着影響循環的性能。

這適用於Chrome,Edge和Firefox,它們都顯示內聯代碼(不調用函數)的標準迭代(for循環)最快,接下來比標準迭代慢10%,是標準迭代一個函數調用(如forEach),然後forEach每次迭代的開銷超過2X。 (每個測試使用15-20比1代碼餘額,即迭代內的代碼比迭代所需的最小代碼長15-20倍。所以一行爲for,forEach循環和循環內部的10-15行代碼。)

如果你正在處理一個數千到數萬的數組,那麼這個差異是不值得打擾的,如果你是處理成千上萬到數百萬的數量,你應該避免使用forEach

注:我沒有在類型數組上測試forEach,因爲這種情況不適用。

測試在

  • 的Chrome版本50.0.2661.37的β-M
  • 火狐46.0b2
  • 邊緣25.10586
+0

這對我來說似乎是正確的。一個音符雖然。對於類型化數組,「forEach」顯着更快(〜10x),幾乎沒有例外。但是'forEach'在普通數組上也可以快得多。速度很大程度上取決於你在做什麼。我個人發現,目前的邊緣瀏覽器每次都會更快地「forEach」。你應該總是先測試它。 – Andrew

+0

@Andrew我經常測試這些東西,但必須承認我還沒有測試'forEach'(等)幾個月。如果'forEach'終於使它自己值得使用,我會再看看並改變我的答案。 – Blindman67

+0

您可能仍然會發現它們較慢;再次,這取決於你在做什麼以及你如何做。我的回調通常非常簡單(通常是不可變的)。上一次我必須做一個性能測試(大約六個星期前),我發現'forEach'迭代一個常規數組的速度快了20倍 - 所以我認爲我做錯了。重新測試,再次快了17倍。我真的懷疑這取決於你的代碼以及你的JS引擎可以執行什麼優化。但是我認爲如果perf很重要或者你有一個性能問題(如問題),切換可能會有很大幫助。 – Andrew

相關問題