在前端開發(fā)中會(huì)遇到一些頻繁的事件觸發(fā),例如:
- window的resize奋救、scroll
- mousedown岭参、mousemove
- keyup、keydown
頻繁的觸發(fā)會(huì)造成卡頓現(xiàn)象尝艘,為了解決這個(gè)問題演侯,一般有兩種解決方案:
- debounce防抖
- throttle節(jié)流
防抖
防抖的原理是:你盡管觸發(fā)事件,但是我一定在事件觸發(fā)n秒后執(zhí)行背亥,如果一個(gè)事件觸發(fā)n秒內(nèi)又觸發(fā)了這個(gè)事件秒际,那我就以新的事件的時(shí)間為準(zhǔn),n秒后執(zhí)行狡汉,總之就是要等你觸發(fā)事件n秒內(nèi)不再觸發(fā)事件娄徊。
<html>
<head>
<meta charset="utf-8">
<style>
#container {
width: 100%;
height: 200px;
line-height: 200px;
text-align: center;
color: #000;
background-color: #ddd;
}
</style>
</head>
<body>
<div id="container"></div>
</body>
<script>
var count = 1;
var container = document.getElementById('container')
function getUserAction() {
container.innerHTML = count++
}
container.onmousemove = getUserAction
</script>
</html>
第一版
function debounce(func, wait) {
var timeout
return function() {
clearTimeout(timeout)
timeout = setTimeout(func, wait)
}
}
this
getUserAction函數(shù)中,在不使用debounce時(shí)盾戴,this指向的是container的dom元素寄锐,在使用debounce時(shí),this指向的是window尖啡,修改下代碼修正this指向
function debounce(func, wait) {
var timeout
return function() {
var context = this
clearTimeout(timeout)
timeout = setTimeout(function() {
func.apply(context)
}, wait)
}
}
event對象
JavaScript在事件處理函數(shù)中會(huì)提供事件對象event橄仆,但在使用debounce時(shí),event對象為undefined衅斩,修正下event對象問題
function debounce(func, wait) {
var timeout
return function() {
var context = this
var args = arguments
clearTimeout(timeout)
timeout = setTimeout(function() {
func.apply(context, args)
}, wait)
}
}
返回值
getUserAction函數(shù)可能存在返回值盆顾,所以我們要返回函數(shù)執(zhí)行的結(jié)果
function debounce(func, wait) {
var timeout, reslut
return function() {
var context = this
var args = arguments
clearTimeout(timeout)
timeout = setTimeout(function() {
reslut = func.apply(context, args)
}, wait)
return reslut
}
}
立即執(zhí)行
立即執(zhí)行需求是,我不想非要等到事件停止觸發(fā)后才執(zhí)行畏梆,我希望能立即執(zhí)行函數(shù)椎扬,然后等到停止觸發(fā)n秒后惫搏,才可以重新執(zhí)行
function debounce(func, wait, immediate) {
var timeout, reslut
return function() {
var context = this
var args = arguments
if(timeout) clearTimeout(timeout)
if(immediate) {
// 如果已經(jīng)執(zhí)行過,不再執(zhí)行
var callNow = !timeout
timeout = setTimeout(function() {
timeout = null
}, wait)
if(callNow) reslut = func.apply(context, args)
} else {
timeout = setTimeout(function() {
reslut = func.apply(context, args)
}, wait)
}
return reslut
}
}
取消
可以支持取消debounce函數(shù)蚕涤,比如說我debounce的時(shí)間為10秒,immediate為true铣猩,這樣的話揖铜,我只有等10秒之后才能重新觸發(fā)事件,現(xiàn)在我希望能主動(dòng)取消debounce达皿,可以再次觸發(fā)函數(shù)
function debounce(func, wait, immediate) {
var timeout, reslut
var debounced = function() {
var context = this
var args = arguments
if(timeout) clearTimeout(timeout)
if(immediate) {
// 如果已經(jīng)執(zhí)行過天吓,不再執(zhí)行
var callNow = !timeout
timeout = setTimeout(function() {
timeout = null
}, wait)
if(callNow) reslut = func.apply(context, args)
} else {
timeout = setTimeout(function() {
reslut = func.apply(context, args)
}, wait)
}
return reslut
}
debounced.cancel = function() {
clearTimeout(timeout)
timeout = null
}
return debounced
}
完整示例代碼
<html>
<head>
<meta charset="utf-8">
<style>
#container {
width: 100%;
height: 200px;
line-height: 200px;
text-align: center;
color: #000;
background-color: #ddd;
}
</style>
</head>
<body>
<div id="container"></div>
<button id="cancel">取消</button>
</body>
<script>
var count = 1;
var container = document.getElementById('container')
var cancel = document.getElementById('cancel')
function getUserAction(e) {
container.innerHTML = count++
console.log(e)
}
var debounceFun = debounce(getUserAction, 10000, true)
container.onmousemove = debounceFun
cancel.onclick = function() {
debounceFun.cancel()
}
function debounce(func, wait, immediate) {
var timeout, reslut
var debounced = function() {
var context = this
var args = arguments
if(timeout) clearTimeout(timeout)
if(immediate) {
// 如果已經(jīng)執(zhí)行過,不再執(zhí)行
var callNow = !timeout
timeout = setTimeout(function() {
timeout = null
}, wait)
if(callNow) reslut = func.apply(context, args)
} else {
timeout = setTimeout(function() {
reslut = func.apply(context, args)
}, wait)
}
return reslut
}
debounced.cancel = function() {
clearTimeout(timeout)
timeout = null
}
return debounced
}
</script>
</html>