最近有個亂七八糟的產品,又加了個亂七八糟的需求,結果還被懟了亂七八糟,阿西吧!css
在頁面設置兩個定時器,一個倒計時,另外一個輪詢,有衝突(臆想)。數組
最基礎的定時器是 setTimeout
,指定 xx ms 後執行。性能優化
來看它的一個缺陷:性能
for () {
// 運行了 1s
}
// 指定 100ms 後執行
setTimeout('console.log(1)', 100);
複製代碼
打印日誌的時間在 1s 後,而不是咱們預期的 100ms。優化
衆所周知 js 是單線程的,在線程被佔用的狀況下,沒法進行另外一個操做,只能加入到執行隊列中,而一旦線程空閒時,會當即執行隊列中的操做。ui
所以,setTimeout
的執行時間是不太精確的。spa
setInterval
主要用來重複執行,指定 xx ms 間隔。線程
它是在各個時間點加入到執行隊列中,等進程空閒後執行。可能出現某個間隔被跳過的狀況:日誌
setInterval(function longTime() {
for () {
// 運行了 300ms
}
}, 100);
複製代碼
longTime
運行期間,其它 longTime
副本也被加入到隊列中,多個只執行最早加入的那個,其它將被跳過。code
這個小缺陷能夠用高級點的技巧避免:
setTimeout(function foo() {
// 一些操做
// 遞歸,作到相似 setInterval 的效果
// 且比 setInterval 更可靠,保證了間隔不被跳過
setTimeout(foo, 100);
}, 100);
複製代碼
定時器的延遲執行功能,可應用到許多場景,例如倒計時等等。更多的是性能優化這一塊。
假設有這樣的場景:
const arr = new Array(1000);
for (let i = 0; i < arr.length; i++) {
// 操做數組的每一項,同步的
// 運行了 100ms
}
// 總共耗時 1000x0.1 = 100s
複製代碼
上面的場景,界面在 100s 內都無響應,由於 js 線程一直被佔用,沒法執行其它操做。
使用定時器把數組分紅一塊一塊處理:
const arr = new Array(1000);
const chunkSize = 1; // 分塊大小
setTimeout(function foo() {
const arrChunk = arr.splice(0, chunkSize);
// 操做分塊後的數組 arrChunk
// 運行了 100ms * chunkSize
if (arr.length > 0) {
// 100ms 的緩衝期,讓界面不至於失去響應
setTimeout(foo, 100);
}
}, 100);
複製代碼
節流和防抖兩個概念太類似了,每次都會把它倆搞混。。。都是減小觸發頻率,提升性能,最主要的差異應該是觸發時間。
setInterval
的執行機制,觸發屢次時,在指定的時間間隔內,只有第一次的纔會執行,其它的跳過(手動)。setTimeout
相似,延遲執行,觸發屢次時,只執行最後一個,其它的被清除(手動)。應用場景上也能混用,,,大概瞭解下就好了
// 大多用在 scroll 上的節流
// 也可使用 px 單位,好比 10px
HTMLElement.addEventListener('scroll', function throttle() {
const ts = Date.now();
// 上次調用時間過了 100ms
if (ts - lastInvokeTs > 100) {
lasInvokeTs = ts;
// 一些操做
}
});
// 大多用在 keyup、resize 上的防抖
HTMLElement.addEventListener('keyup', function debounce() {
// 延遲到觸發時 100ms 後
clearTimeout(timer);
timer = setTimeout(function () {
// 一些操做
}, 100);
});
複製代碼
針對 Css 渲染方面的節流能夠考慮原生更流暢的 API requestAnimationFrame
:
HTMLElement.addEventListener('scroll', function foo() {
if (!changing) {
requestAnimationFrame(function () {
// 一些操做
changing = false;
});
}
changing = true;
});
複製代碼
css-tricks 上更好的一篇解釋防抖節流的文章。
通常來講頁面裏同時設置幾個定時器問題不大,js 的執行速度很快,偏差也大不到哪去,何況 ms 級別的偏差也感受不到。
節流和防抖仍是比較混,阿西吧!