JavaScript中定時(shí)控制Throttle、Debounce和Immediate詳解
前言
我們稱這些行為events(事件),和響應(yīng)callbacks(回調(diào))。連續(xù)的事件流被稱為event stream(事件流)。這些行為發(fā)生的速度不是我們能手動(dòng)控制的。但是我們可以控制何時(shí)和如何激活正確的響應(yīng)。有一些技術(shù)為我們提供精確的控制。
Throttle
在現(xiàn)代瀏覽器中,幀速率為60fps是流暢性能的目標(biāo),給定我們16.7ms的時(shí)間預(yù)算用于響應(yīng)一些事件所有需要的更新。這樣可以推斷,如果每秒發(fā)生n個(gè)事件并且回調(diào)執(zhí)行,需要t秒的時(shí)間,為了流暢運(yùn)行,
1 / n >= t
如果t以毫秒為單位,
1000 / n >= t
如果你曾經(jīng)使用mousemove事件,你會(huì)知道產(chǎn)生mousemove事件的數(shù)量每秒可以超過60次。如果我們的回調(diào)需要超過16.7ms,那就開始凌亂了。
var then = 0; function log() { var now = Date.now(); if (1000 / (now - then) > 60) { console.log('It\'s over 9000!!!'); } then = now; } window.onmousemove = log;
實(shí)現(xiàn)
Throttle 允許我們限制我們激活響應(yīng)的數(shù)量。我們可以限制每秒回調(diào)的數(shù)量。反過來,也就是說在激活下一個(gè)回調(diào)之前要等待多少時(shí)間;
var delta = 1000; var then = 0; function log() { console.log('foo'); } function throttledLog() { var now = Date.now(); if (now - then >= delta) { log(); then = now; } }; window.onmousemove = throttledLog;
我們可以用 fps替換delta,并推斷出不同的代碼。
var fps = 60; ... function throttledLog() { var now = Date.now(); if (1000 / (now - then) < = fps) { log(); then = now; } }; window.onmousemove = throttledLog;
我們也可以通過使用setTimeout來實(shí)現(xiàn)相同的結(jié)果。 但是,不是檢查時(shí)間差,而是檢查狀態(tài)變化。
第一次,我們可以安全地激活回調(diào)。一旦完成,只有在等待 delta 時(shí)間之后才能再次激活回調(diào)。
var delta = 1000; var safe = true; function log() { console.log('foo'); } function throttledLog() { if (safe) { log(); safe = false; setTimeout(function() { safe = true; }, delta); } }; window.onmousemove = throttledLog;
Debounce
這個(gè)術(shù)語-去抖動(dòng) 來自電子學(xué)的領(lǐng)域,手動(dòng)開關(guān)輸入的信號(hào)被發(fā)送到數(shù)字電路中。在電子學(xué)中,當(dāng)你按一個(gè)物理按鈕一次,數(shù)字電路可能讀到多個(gè)按壓,因?yàn)榘粹o的物理屬性(金屬觸點(diǎn),彈簧,磨損件等)。
去抖動(dòng)意味著采集到的所有這些波動(dòng)的信號(hào),并把它們當(dāng)作一個(gè)。
例子
一個(gè)簡單的例子已經(jīng)存在于JS中:keydown vs keyup。假設(shè)您正在處理一個(gè)項(xiàng)目,并且需要輸入內(nèi)容。但是你想要每次敲擊鍵盤得到一個(gè)字符。輸入時(shí),如果長按一個(gè)鍵,keydown事件將連續(xù)被觸發(fā),但是 keyup 事件只有在按鍵被釋放時(shí)才會(huì)觸發(fā)。
window.onkeyup = function() { console.log('onkeyup'); } window.onkeydown = function() { console.log('onkeydown'); }
這種行為上的差異對(duì)于確定輸入是否已完成是有用的。在示例場(chǎng)景中,它是你將使用的keyup事件。在某種程度上,我們可以說keydown 是原始輸入,keyup 是去抖動(dòng)輸入。
實(shí)現(xiàn)
當(dāng)事件發(fā)生時(shí),我們不會(huì)立即激活回調(diào)。相反,我們等待一定的時(shí)間并檢查相同的事件是否再次觸發(fā)。如果是,我們重置定時(shí)器,并再次等待。如果在等待期間沒有發(fā)生相同的事件,我們就立即激活回調(diào)。
var delta = 1000; var timeoutID = null; function log() { console.log('foo'); } function debouncedLog() { clearTimeout(timeoutID); // reset timer timeoutID = setTimeout(function() { // wait for some time // and check if event happens again log(); }, delta); }; window.onkeydown = debouncedLog;
Immediate
Immediate是Debounce的精確版本。比起 Debounce 的 等待后續(xù)事件觸發(fā),然后再激活回調(diào),Immediate 是 立即激活回調(diào),然后等待后續(xù)事件在一定時(shí)間內(nèi)觸發(fā)。
實(shí)現(xiàn)
就像Throttle的情況一樣,我們需要一個(gè)狀態(tài)變量來檢查是否應(yīng)該激活我們的回調(diào)。我們?cè)贒ebounce不需要一個(gè),因?yàn)閠imeoutID隱式管理這部分。
var delta = 1000; var timeoutID = null; var safe = true; function log() { console.log('foo'); } function immediatedLog() { if (safe) { log(); safe = false; } clearTimeout(timeoutID); timeoutID = setTimeout(function() { safe = true; }, delta); }; window.onkeydown = immediatedLog;
總結(jié)
以上就是這篇文章的全部內(nèi)容了,在這篇文章中,我們已經(jīng)探索了用作定時(shí)函數(shù)的最常見的技術(shù)。希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。
- javascript函數(shù)的節(jié)流[throttle]與防抖[debounce]
- JavaScript性能優(yōu)化之函數(shù)節(jié)流(throttle)與函數(shù)去抖(debounce)
- 詳解JavaScript節(jié)流函數(shù)中的Throttle
- JavaScript 節(jié)流函數(shù) Throttle 詳解
- javascript中的throttle和debounce淺析
- Javascript Throttle & Debounce應(yīng)用介紹
- Javascript節(jié)流函數(shù)throttle和防抖函數(shù)debounce
相關(guān)文章
JavaScript實(shí)現(xiàn)異步獲取表單數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)異步獲取表單數(shù)據(jù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05JS回調(diào)函數(shù)基本定義與用法實(shí)例分析
這篇文章主要介紹了JS回調(diào)函數(shù)基本定義與用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了javascript回調(diào)函數(shù)基本概念、功能、使用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-05-05關(guān)于js復(fù)制內(nèi)容到瀏覽器剪貼板報(bào)錯(cuò):Cannot read properties of&n
這篇文章主要給大家介紹了關(guān)于js復(fù)制內(nèi)容到瀏覽器剪貼板報(bào)錯(cuò):Cannot read properties of undefined (reading ‘writeText‘)的解決方案,文中給出了詳細(xì)的原因分析和解決方案,需要的朋友可以參考下2024-01-01使用mpvue搭建一個(gè)初始小程序及項(xiàng)目配置方法
這篇文章主要介紹了使用mpvue搭建一個(gè)初始小程序及項(xiàng)目配置方法,需要的朋友可以參考下2018-12-12BootStrap Validator使用注意事項(xiàng)(必看篇)
針對(duì)bootstrap2和bootstrap3有不同的版本,在使用bootstrap validator時(shí)需要了解其注意事項(xiàng),下面小編把我遇到的注意事項(xiàng)分享給大家,供大家參考2016-09-09BootStrap Fileinput插件和Bootstrap table表格插件相結(jié)合實(shí)現(xiàn)文件上傳、預(yù)覽、提交的導(dǎo)入E
這篇文章主要介紹了BootStrap Fileinput插件和Bootstrap table表格插件相結(jié)合實(shí)現(xiàn)文件上傳、預(yù)覽、提交的導(dǎo)入Excel數(shù)據(jù)操作步驟,需要的朋友可以參考下2017-08-08