我知道計時器已經成為許多人在日常任務中使用的功能已有一段時間了。在 JavaScript 世界中,計時器通常使用 setTimeout 或 setInterval 函數來實現,如果你這樣做的話,壞消息是這不是一個好的做法,我將嘗試解釋原因。
在開始解釋我的想法之前,我有一個問題要問你:你能用手錶報錯時間嗎?
如果您的答案是肯定的,我很抱歉浪費了您的寶貴時間,因為這篇文章不屬於您。
另一方面,如果您的答案是否定的,我將解釋為什麼使用 setTimeout 或 setInterval 就像使用損壞的手錶來獲取時間。
首先,讓我們考慮以下程式碼片段
function test() { let i = 0; setTimeout(() => console.log("hello"), 0); while (i < 5) { console.log("number ", i); i += 1; } console.log("world");
如果您在瀏覽器控制台中執行此程式碼片段,您將得到以下結果
此行為是由於setTimeout 將回調添加到瀏覽器隊列中,以便在空閒時處理它(沒有任務要做) 換句話說,回調傳遞給setTimeout 的優先級較低
現在,知道了這一點,我認為您將很難使用 setTimeout 函數來實現計時器,因為您可以同時擁有 2 個甚至 10 個刻度(取決於您的瀏覽器的繁忙程度)。這對於調試來說將是一場噩夢,但是我們有更好的解決方案嗎?
為了提供更好的實作計時器的方法,我們應該使用requestAnimationFrame 函數,因為它告訴瀏覽器在下一次繪製之前執行回調(換句話說,在UI 發生任何更改之前)
這裡的差異非常微妙,所以最好透過程式碼來理解。讓我們收回先前的程式碼片段並稍微調整一下以比較 setTimeout 和 requestAnimationFrame
function testWithAnimationFrame() { let i = 0; setTimeout(() => console.log("hello"), 0); requestAnimationFrame(() => console.log("tell me the next paint")); while (i < 5) { console.log("number ", i); i += 1; } console.log("world"); }
在這個範例中,我們可以看到,在 Chrome 上運行時,setTimeout 在 requestAnimationFrame 之前運行(儘管在極少數情況下會發生相反的情況)
但是如果你在 Firefox 上運行它,這將是輸出
這看起來可能令人困惑,但如果你稍微注意一下,你會發現執行過程中沒有發生任何繪畫,因此如何處理這種情況取決於瀏覽器。
現在,如果我們可以調整程式碼片段以使瀏覽器重新繪製頁面,讓我們看看會發生什麼
function testWithAnimationFrame2() { let i = 0; setTimeout(() => console.log("hello"), 0); requestAnimationFrame(() => console.log("tell me the next paint")); while (i < 5) { console.log("number ", i); i += 1; document.body.style.backgroundColor = "red"; } console.log("world"); }
這是 Chrome 上的輸出
這是 Firefox 中的輸出
正如您在日誌中看到的,當瀏覽器在 UI 中進行更改時,requestAnimationFrame 函數將始終優先於其他計劃的回調。
因為在網路上,我們不斷地執行重繪,requestAnimationFrame 是實現計時器的明顯選擇。
函數僅接受回呼作為參數。為了向回調提供上下文,它應該採用一個時間戳,指示基於頁面初始渲染時間的前一幀結束的時間。
該函數將傳回一個代表請求標識符的整數,如果您希望使用 cancelAnimationFrame 函數取消請求,這會很有用。
要實現秒錶,有一些要求:
考慮到所有這些要求,以下程式碼片段將為您建立一個秒錶
我知道這可能是一篇很長的文章,但相信您會喜歡它。無論如何,如果您有任何疑問或有任何建議,請隨時與我聯繫。
感謝您閱讀本文,再見?
以上是您不需要設定超時的詳細內容。更多資訊請關注PHP中文網其他相關文章!