JavaScript 防抖和節(jié)流詳解
防抖
自動門感應(yīng)到有人,打開門,并且開始5秒倒計時,在 5 s 內(nèi)有另外一個人靠近到門,門感應(yīng)到人,重新5秒倒計時
當(dāng)事件被觸發(fā)時,設(shè)定一個延遲,若期間事件又被觸發(fā),則重新設(shè)定延遲,直到延遲結(jié)束,執(zhí)行動作 (防止多次觸發(fā))
web 應(yīng)用上面
- 改變頁面大小的統(tǒng)計
- 滾動頁面位置的統(tǒng)計
- 輸入框連續(xù)輸入的請求次數(shù)控制
一開始,點(diǎn)擊按鈕,console.log('pay money')
<body>
<button id="btn">click</button>
</body>
<script>
const btn = document.getElementById('btn')
function payMoney() {
console.log('pay money');
}
btn.addEventListener('click', payMoney)
</script>
定義 debounce
const btn = document.getElementById('btn')
function payMoney() {
console.log('pay money');
}
function debounce(func) {
// 在函數(shù)里面返回函數(shù) , 只有當(dāng)點(diǎn)擊的時候才返回該函數(shù)
return function () {
func()
}
}
btn.addEventListener('click', debounce(payMoney))
設(shè)置延時
const btn = document.getElementById('btn')
function payMoney() {
console.log('pay money');
}
function debounce(func, delay) {
return function () {
setTimeout(_ => func(), delay)
}
}
btn.addEventListener('click', debounce(payMoney, 1000))
清除延時:未能執(zhí)行
原因
每次點(diǎn)擊的時候就會執(zhí)行返回函數(shù)里面的內(nèi)容
每次點(diǎn)擊的執(zhí)行函數(shù)都是獨(dú)立的,互不干涉
正因為他們之間沒有聯(lián)系,清除延時在這里完全沒有起作用
要讓這些獨(dú)立的執(zhí)行函數(shù)之間有聯(lián)系,需要用到作用域鏈(閉包)
const btn = document.getElementById('btn')
function payMoney() {
console.log('pay money');
}
function debounce(func, delay) {
return function () {
let timer
clearInterval(timer)
timer = setTimeout(_ => func(), delay)
}
}
btn.addEventListener('click', debounce(payMoney, 1000))
將 timer 放在返回函數(shù)的外圍,這樣在定義監(jiān)聽事件的同時,就定義了 timer變量
因為作用域鏈,所有獨(dú)立的執(zhí)行函數(shù)都能訪問到這個timer變量
而且現(xiàn)在這個timer變量只創(chuàng)建了一次。是唯一的,我們只不過不斷給timer賦值進(jìn)行延時而已
每個清除延時就是清除上一個定義的延時,相當(dāng)于多個函數(shù)共用同一個外部變量
const btn = document.getElementById('btn')
function payMoney() {
console.log('pay money');
}
function debounce(func, delay) {
let timer
return function () {
clearInterval(timer)
timer = setTimeout(_ => func(), delay)
}
}
btn.addEventListener('click', debounce(payMoney, 1000))
此時的代碼,this 是指向 window ?
因為回調(diào)的原因,運(yùn)行時已經(jīng)在Window下了
const btn = document.getElementById('btn')
function payMoney() {
console.log('pay money');
console.log(this);
}
function debounce(func, delay) {
let timer
return function () {
clearInterval(timer)
timer = setTimeout(_ => func(), delay)
}
}
btn.addEventListener('click', debounce(payMoney, 1000))
解決辦法
在 setTimeout 之前將 this 保存下來,此時的 this 是指向按鈕的
const btn = document.getElementById('btn')
function payMoney() {
console.log('pay money');
console.log(this);
}
function debounce(func, delay) {
let timer
// 只有當(dāng)點(diǎn)擊的時候,才返回此函數(shù),所以 this 是指向按鈕的
return function () {
let context = this
clearInterval(timer)
timer = setTimeout(_ => {
func.apply(context)
}, delay)
}
}
btn.addEventListener('click', debounce(payMoney, 1000))
考慮參數(shù)的問題,添加 arg
const btn = document.getElementById('btn')
function payMoney() {
console.log('pay money');
console.log(this);
}
function debounce(func, delay) {
let timer
return function () {
let context = this
let args = arguments
clearInterval(timer)
timer = setTimeout(_ => {
func.apply(context)
console.log(context, args);
}, delay)
}
}
btn.addEventListener('click', debounce(payMoney, 1000))
節(jié)流
先觸發(fā)一次后,防止接下來多次觸發(fā)
滾動屏幕:統(tǒng)計用戶滾動屏幕的行為來作出相應(yīng)的網(wǎng)頁反應(yīng)
當(dāng)用戶不斷進(jìn)行滾動,就會不斷產(chǎn)生請求,相應(yīng)也會不斷增加,容易導(dǎo)致 ⛔️ 網(wǎng)絡(luò)阻塞
我們就可以在觸發(fā)事件的時候就馬上執(zhí)行任務(wù),然后設(shè)定時間間隔限制,在這段時間內(nèi)不管用戶如何進(jìn)行滾動都忽視操作
在時間到了以后如果監(jiān)測到用戶有滾動行為,再次執(zhí)行任務(wù)。并且設(shè)置時間聞隔
首先,寫個改變頁面尺寸的同時改變頁面背景顏色的代碼
function coloring() {
let r = Math.floor(Math.random() * 255)
let g = Math.floor(Math.random() * 255)
let b = Math.floor(Math.random() * 255)
document.body.style.background = `rgb(${r}, ${g}, $)`
}
window.addEventListener('resize', coloring)
function throttle(func, delay) {
let timer
return function () {
timer = setTimeout(_ => {
func()
}, delay)
}
}
window.addEventListener('resize', throttle(coloring, 2000))
判斷觸發(fā)的事件是否在時間間隔內(nèi)
- 不在:觸發(fā)事件
- 在:不觸發(fā)事件
function throttle(func, delay) {
let timer
return function () {
// timer 被賦值了,直接返回,即不執(zhí)行任務(wù)
if (timer) {
return
}
// 此時 timer 沒被賦值,或 timer 已經(jīng)執(zhí)行完了
// 為 timer 賦值進(jìn)行延時執(zhí)行
timer = setTimeout(_ => {
func()
// 延遲執(zhí)行以后我們要清空timer的值
timer = null
}, delay)
}
}
window.addEventListener('resize', throttle(coloring, 2000))
解決 this 指向(雖然當(dāng)前的這個例子就是在 Window 下的)
function throttle(func, delay) {
let timer
return function () {
let context = this
let args = arguments
// timer 被賦值了,直接返回,即不執(zhí)行任務(wù)
if (timer) {
return
}
// 此時 timer 沒被賦值,或 timer 已經(jīng)執(zhí)行完了
// 為 timer 賦值進(jìn)行延時執(zhí)行
timer = setTimeout(_ => {
func.apply(context, args)
// 延遲執(zhí)行以后我們要清空timer的值
timer = null
}, delay)
}
}
window.addEventListener('resize', throttle(coloring, 1000))
節(jié)流核心:事件間隔 另一種常見的時間間隔就是用Date對象
function throttle(func, delay) {
// 我們要和前一個時間點(diǎn)進(jìn)行比較才能確定是否已經(jīng)過了時間間隔
// 在返回函數(shù)外圍,避免每次執(zhí)行都被自動修改
let pre = 0
return function () {
// 保存執(zhí)行函數(shù)當(dāng)時的時間
let now = new Date()
// 剛開始,一定會執(zhí)行
if (now - pre > delay) {
// 已經(jīng)過了時間間隔,就可以執(zhí)行函數(shù)了
func()
// 執(zhí)行后,重新設(shè)置間隔點(diǎn)
pre = now
}
}
}
window.addEventListener('resize', throttle(coloring, 1000))
解決參數(shù)問題
function throttle(func, delay) {
let pre = 0
return function () {
let context = this
let args = arguments
let now = new Date()
if (now - pre > delay) {
func.apply(context, args)
pre = now
}
}
}
window.addEventListener('resize', throttle(coloring, 1000))
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
- JavaScript函數(shù)防抖動debounce
- 通過實(shí)例講解JS如何防抖動
- JavaScript運(yùn)動框架 解決防抖動問題、懸浮對聯(lián)(二)
- JavaScript中防抖和節(jié)流的區(qū)別及適用場景
- JavaScript中防抖和節(jié)流的實(shí)戰(zhàn)應(yīng)用記錄
- JavaScript深入理解節(jié)流與防抖
- JavaScript防抖與節(jié)流的實(shí)現(xiàn)與注意事項
- JavaScript的防抖和節(jié)流一起來了解下
- JavaScript中函數(shù)的防抖與節(jié)流詳解
- javascript的防抖和節(jié)流你了解嗎
- 淺談JavaScript節(jié)流與防抖
- 關(guān)于JavaScript防抖與節(jié)流的區(qū)別與實(shí)現(xiàn)
- JavaScript防抖與節(jié)流詳解
- JavaScript防抖動與節(jié)流處理
相關(guān)文章
JS實(shí)現(xiàn)為表格動態(tài)添加標(biāo)題的方法
這篇文章主要介紹了JS實(shí)現(xiàn)為表格動態(tài)添加標(biāo)題的方法,涉及javascript中createCaption方法添加標(biāo)題的技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-03-03
js實(shí)現(xiàn)可旋轉(zhuǎn)的立方體模型
這里給大家分享的是通過js腳本來控制頁面中的正方體轉(zhuǎn)動特效,用戶可以點(diǎn)擊按鈕向右轉(zhuǎn)動,也可以向下轉(zhuǎn)動,結(jié)合自己的需求控制即可。效果非常棒,這里推薦給大家2016-10-10
js apply/call/caller/callee/bind使用方法與區(qū)別分析
js apply/call/caller/callee/bind使用方法與區(qū)別分析,需要的朋友可以參考下。2009-10-10
text-align:justify實(shí)現(xiàn)文本兩端對齊 兼容IE
對于text-align 我們再熟悉不過了,可是它有個justify屬性,平時很少用到,就鮮為人知了。justify是一種文本靠兩邊布局方式,一般應(yīng)用于書刊雜志排版;合理運(yùn)用text-align:justify 有時會省去很多開發(fā)的時間,通過本文介紹text-align:justify實(shí)現(xiàn)文本兩端對齊 兼容IE2015-08-08
javascript簡單實(shí)現(xiàn)類似QQ頭像彈出效果的方法
這篇文章主要介紹了javascript簡單實(shí)現(xiàn)類似QQ頭像彈出效果的方法,可實(shí)現(xiàn)簡單的頁面元素彈出效果,具有一定參考借鑒價值,需要的朋友可以參考下2015-08-08
js窗口關(guān)閉提示信息(兼容IE和firefox)
這篇文章主要介紹了當(dāng)關(guān)閉窗口的時候,顯示窗口提示信息,友好的進(jìn)行提示,防止丟失重要信息,需要的朋友可以參考一下2015-10-10
JavaScript實(shí)現(xiàn)動態(tài)增刪表格的方法
本篇文章主要介紹了JavaScript實(shí)現(xiàn)動態(tài)增刪表格,可以實(shí)現(xiàn)表格增加和刪除數(shù)據(jù)的功能,非常具有實(shí)用價值,有興趣的可以了解一下2017-03-03
javascript實(shí)現(xiàn)劃詞標(biāo)記+劃詞搜索功能
javascript實(shí)現(xiàn)劃詞標(biāo)記+劃詞搜索功能...2007-03-03

