零延遲setTimeout(fn,0)的應用

劉權德 Chad Liu 2021/12/26 22:16:49
947

前言

在js上可以透過setTimeout(fn,0) 0延遲(Zero Delay)完成dom渲染完成後的非同步執行效果。

 

瀏覽器中主要的JS程序、圖形渲染、事件觸發三大流程,在JS程序執行期間,圖形引擎會處在駐列等待的狀態,等JS排程內的工作完成後執行,事件觸發則是接續在駐列排程後等待執行,而透過setTimeout(fn,0)的效果會在js程序及圖形渲染完成後盡快(瀏覽器中調用最小間隔是4ms)執行fn內的工作。

 

javascript單一執行序運作說明

console.log('1')
setTimeout(() => {
 console.log('2')
}, 0)
console.log('3')

這樣的程式碼內容印出的結果是

1
3
2

雖然我們在時間間格上設置為0,但實際運作上不會馬上執行setTimeout內呼叫的fn內容,而是等到JS程序中正在駐列中的所有任務都執行完畢才接續執行。

 

範例說明

定時透過API取回資料並接續在畫面上後,因元件高度變長產生垂直捲軸,需將捲軸設置在最下方。

如果在設置資料後同時設定捲軸位置,會因畫面尚未渲染完畢,資料容器高度還未渲染成真實設置資料後的高度,導致捲軸指定的位置與實際容器高度有差距而無法達成至底的效果。(請見上圖)

而調整流程透過settimeout(fn,0)的改寫方式,在接到資料後把設置捲軸高度事件寫在fn中,等待資料設置及畫面渲染完畢後才會執行設置捲軸的高度位置,而達到期望的效果將捲軸至底的效果。(請見下圖)

後記

使用setTimeout需要注意應用的方式以免影響了效能;使用得宜則會是很方便的小技巧。

若有使用框架如Vue、React、Angular,則可參考以下關鍵字來找到完成元件渲染生命週期適合的效果控制時機。

Vue:Vue.nextTick()

React:componentDidMount()、componentDidUpdate()

Angular:ngAfterContentChecked()、ngAfterViewChecked()

 

參考資料

https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

https://vuejs.org/v2/api/index.html#Vue-nextTick

https://zh-hant.reactjs.org/docs/react-component.html

https://angular.tw/guide/lifecycle-hooks

 

劉權德 Chad Liu