簡體   English   中英

requestAnimationFrame [now] vs performance.now()時間差異

[英]requestAnimationFrame [now] vs performance.now() time discrepancy

假設:rAF now時間是在所有回調都被觸發時計算的。 因此,在調用該幀的第一個回調之前發生的任何阻塞now都不會影響rAF並且它是准確的 - 至少對於第一次回調而言。

在觸發rAF集之前進行的任何performance.now()測量應該早於now rAF。

測試:記錄before任何事情發生before的基線時間)。 設置下一個rAF。 now比較rAF和實際performance.now() before看看它們有多么不同。

預期成績:

 var before = performance.now(), frames = ["with blocking", "with no blocking"], calls = 0; requestAnimationFrame(function frame(rAFnow) { var actual = performance.now(); console.log("frame " + (calls + 1) + " " + frames[calls] + ":"); console.log("before frame -> rAF now: " + (rAFnow - before)); console.log("before frame -> rAF actual: " + (actual - before)); if (++calls < frames.length) { before = actual; requestAnimationFrame(frame); } }); // blocking for (var i = 0, l = 0; i < 10000000; i++) { l += i; } 

觀察:當幀開始之前存在阻塞時,即使對於第一幀,rAF now時間有時也是不正確的。 有時,第一幀now實際上是比before記錄的時間更早的時間。

無論是否在幀之前發生阻塞,幀內時間rAFnow都會比之前的幀before時間before我進行第一次測量設置rAF時。 這也可以在沒有任何阻塞的情況下發生,盡管這種情況很少見。

(我在大多數時間都在第一個阻塞幀上出現時間錯誤。在其他阻塞幀上出現問題的情況比較少見,但如果你嘗試運行幾次,偶爾會發生這種情況。)

通過更廣泛的測試,我發現在回調之前阻塞的不良時間:100幀中的1%,沒有阻塞:來自~400幀的0.21645021645021645%,似乎是由用戶打開窗口或其他一些潛在的CPU密集型操作引起的。

所以這是相當罕見的,但問題是這根本不會發生。 如果你想用它們做有用的事情,模擬時間,動畫等,那么你需要那些時間才有意義。

我已經考慮到了人們所說的話,但也許我仍然不理解事情的運作方式。 如果這是所有的規格,我會喜歡一些偽代碼來鞏固它在我的腦海里。

更重要的是,如果有人對如何解決這些問題有任何建議,那將是非常棒的。 我唯一能想到的是自己的performance.now()測量每一幀並使用它 - 但它看起來有點浪費,讓它在每一幀上有效地運行兩次,在任何觸發事件之上等等。

傳遞給requestAnimationFrame()回調的時間戳是動畫幀開始的時間。 在同一幀期間調用的多個回調都接收相同的時間戳。 因此,如果performance.now()在參數值之前返回一個時間,那將是非常奇怪的,但之后它並不是真的很奇怪。

這是相關規范:

當用戶代理是一種用於與時間戳的文檔文件現在運行的動畫幀的回調,它必須執行下列步驟:

  1. 如果文檔對象的hidden屬性返回的值為true,則中止這些步驟。 [PAGE-VISIBILITY]

  2. 讓回調成為文檔動畫幀回調列表中的條目列表,按照它們添加到列表中的順序排列。

  3. 將文檔的動畫幀回調列表設置為空列表。

  4. 對於回調中的每個條目,按順序:調用Web IDL回調函數, 現在作為唯一參數傳遞,如果拋出異常,則報告異常。

所以你已經為下一個動畫幀注冊了一個回調(假設只有一個)。 勾選滴答滴答,BOOM,該動畫幀的發生時間:

  1. JavaScript運行時會記錄現在的時間和標簽。
  2. 運行時生成已注冊動畫幀回調列表的臨時副本,並清除實際列表(如果事情需要很長時間以至於下一個動畫幀出現,則不會意外調用它們)。
  3. 列表中只有一件事:你的回調。 系統使用now作為參數調用它。
  4. 你的回調開始運行。 也許它以前從未運行過,所以JavaScript優化器可能需要做一些工作。 或者操作系統可能會將線程切換到某些其他系統進程,例如啟動磁盤緩沖區刷新或處理某些網絡流量,或任何其他任何系統進程。
  5. 哦,對,你的回調。 瀏覽器再次獲取CPU並且您的回調代碼開始運行。
  6. 您的代碼調用performance.now()並將其與作為參數傳入的now值進行比較。

因為在步驟1和步驟6之間可能會經過一段短暫但不可忽略的時間,所以performance.now()的返回值可能表示已經過了幾微秒,甚至多於幾微秒。 這是完全正常的行為。

我在chrome上遇到了同樣的問題,其中對performance.now ()調用返回的值高於傳遞給window.requestAnimationFrame ()后續回調的now值。

我的解決方法是在第一個window.requestAnimationFrame () 不是performance.now ()設置before使用now傳遞給回調的。 似乎使用兩個函數中的一個來測量時間可以保證值的進步。

我希望這可以幫助其他任何遭受這個bug的人。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM