我正在制作一個簡單的倒數計時器,它顯示剩余的秒數和設定秒數。當用戶單擊按鈕時,倒計時應該停止并且應該顯示一些文本而不是計時器。在 pc 上一切正常,但如果我的手機使用更差的 cpu,我有時會出現這種意外行為:當用戶單擊按鈕時,文本會顯示幾分之一秒,然后計時器繼續運行。我認為這是由函式運行時呼叫 clearTimeout() 方法引起的,就在呼叫新超時之前,但這篇文章證明我錯了。你知道是什么導致了這種行為,我應該如何解決它?
const finished = () => { // finished() is also called when user clicks a button
// show some thext on the screen
clearTimeout(timeout);
}
const start = document.timeline.currentTime! // Think of it as Date.now(); also returns a ms value; just slightly faster.
const end = start 30000 // the countodwn takes 30 seconds
let timeout:any;
const frame = () => {
const elapsed = Math.floor(end - document.timeline.currentTime!)
if (elapsed <= 0) {
finished()
return
};
let secs: number | string = Math.floor(elapsed / 1000)
let setsecs: number | string = Math.floor((elapsed % 1000) * 0.1)
secs = secs < 10 ? "0" secs : secs
setsecs = setsecs < 10 ? "0" setsecs : setsecs
result.innerText = `Time left: ${secs}.${setsecs}`
timeout = setTimeout(() => requestAnimationFrame(frame), 15 - elapsed % 15) // raf is for optimisation and I'm substracting the timeout by the time that has already passed for drift minimisation
}
frame()
編輯:我設法通過承諾重新創建手機上的緩慢行為:這是代碼
uj5u.com熱心網友回復:
TL;博士
問題
setTimeout和之間的時間太短了clearTimeout。重新安排在后面被解雇clearTimeout。
例子
使用布爾標志來檢查該finished函式是否已被呼叫。
解決方案
TS游樂場
const start = document.timeline.currentTime! // Think of it as Date.now(); also returns a ms value; just slightly faster.
const end = start 3000 // the countodwn takes 3 seconds
let timeout:any;
let finishedCalled = false
const finished = () => { // finished() is also called when user clicks a button
// show some thext on the screen
finishedCalled = true
clearTimeout(timeout)
console.log(`Finished!`)
}
setTimeout(finished, 2000)
const frame = async () => {
if(finishedCalled) return console.log(`Finished called found. Have to be end here.`)
const elapsed = Math.floor(end - document.timeline.currentTime!)
console.log(`Elapsed:`, elapsed)
if (elapsed <= 0) {
finished()
return
};
let secs: number | string = Math.floor(elapsed / 1000)
let setsecs: number | string = Math.floor((elapsed % 1000) * 0.1)
secs = secs < 10 ? "0" secs : secs
setsecs = setsecs < 10 ? "0" setsecs : setsecs
console.log(`Time left: ${secs}.${setsecs}`)
await new Promise((resolve) => setTimeout(resolve, 500));
timeout = setTimeout(() => {
console.log(`Timer fired!`)
requestAnimationFrame(frame)
}, 10) // raf is for optimisation and I'm substracting the timeout by the time that has already passed for drift minimisation
}
frame()
深入挖掘
讓我們以 Node.js 為例,追溯源頭。
clearTimeout叫unenrollunenroll叫emitDestroyemitDestroy===emitDestroyScriptemitDestroyScript叫async_wrap.queueDestroyAsyncIdasync_wrap.queueDestroyAsyncId叫AsyncWrap::EmitDestroyAsyncWrap::EmitDestroy可能會或可能不會立即執行。
到此為止,我們可以知道這是一個異步呼叫,并且可能會在執行之前重新調度。這就是為什么該finished功能無法停止timer.
免責宣告:我不是 C 專家。請隨時改進答案。??
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/470941.html
標籤:javascript 打字稿 递归 计时器
