<!DOCTYPE html>
<html lang="zh-cmn-Hans"><head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="IE=edge, chrome=1">
<title>debounce</title>
<style>
#container{
width: 100%; height: 200px; line-height: 200px; text-align: center; color: #fff; background-color: #444; font-size: 30px;
}
</style>
</head><body>
<div id="container"></div>
<script src="debounce.js"></script>
</body></html>

​debounce.js​​ 文件的代码如下:

var count = 1;
var container = document.getElementById('container');function getUserAction() {
container.innerHTML = count++;
};container.onmousemove = getUserAction;

触发事件,但是我一定在事件触发 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,那我就以新的事件的时间为准,n 秒后才执行,总之,就是要等你触发完事件 n 秒内不再触发事件,

// 第一版
function debounce(func, wait) {
var timeout;
return function () {
clearTimeout(timeout)
timeout = setTimeout(func, wait);
}
}

container.onmousemove = debounce(getUserAction, 1000);

如果我们在 ​​getUserAction​​​ 函数中 ​​console.log(this)​​​,在不使用 ​​debounce​​​ 函数的时候,​​this​​ 的值为:

<div id="container"></div>

但是如果使用我们的 debounce 函数,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 在事件处理函数中会提供事件对象 event,我们修改下 getUserAction 函数:

function getUserAction(e) {
console.log(e);
container.innerHTML = count++;
};

JavaScript 在事件处理函数中会提供事件对象 event,我们修改下 getUserAction 函数:

function getUserAction(e) {
console.log(e);
container.innerHTML = count++;
};// 第三版
function debounce(func, wait) {
var timeout; return function () {
var context = this;
var args = arguments; clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}

返回值

// 第四版
function debounce(func, wait) {
var timeout, result; return function () {
var context = this;
var args = arguments; clearTimeout(timeout)
timeout = setTimeout(function(){
result = func.apply(context, args)
}, wait); return result;
}



我们修复了三个小问题:

  1. this 指向
  2. event 对象
  3. 返回值

立刻执行

我不希望非要等到事件停止触发后才执行,我希望立刻执行函数,然后等到停止触发n秒后,才可以重新触发执行。

// 第五版
function debounce(func, wait, immediate) { var timeout, result;
return function () {
var context = this;
var args = arguments; if (timeout) clearTimeout(timeout);
if (immediate) {
// 如果已经执行过,不再执行
var callNow = !timeout;
timeout = setTimeout(function(){
timeout = null;
}, wait)
if (callNow) result = func.apply(context, args)
}
else {
timeout = setTimeout(function(){
result = func.apply(context, args)
}, wait);
} return result;
}
}

取消

// 第六版
function debounce(func, wait, immediate) { var timeout, result;
var debounced = function () {
var context = this;
var args = arguments; if (timeout) clearTimeout(timeout);
if (immediate) {
// 如果已经执行过,不再执行
var callNow = !timeout;
timeout = setTimeout(function(){
timeout = null;
}, wait)
if (callNow) result = func.apply(context, args)
}
else {
timeout = setTimeout(function(){
result = func.apply(context, args)
}, wait);
}
return result;
}; debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
}; return debounced;
}