我在线上找到了很棒的debounce()
功能代码,但是我很难将其从ES5转换为ES6。
问题如下:当我使用ES5实现时,一切运行正常。调整窗口大小,立即触发console.log()
,随后的调整大小将被忽略,直到指定的500ms之后。
但是,在ES6实施中,第一个调用立即生效...但是每次之后,即使冷却下来,也会 延迟500ms!
如果有人知道我在做什么错,我将非常感谢您的帮助。
示例:
function debounceES5(func, wait, immediate) {
var timeout;
return function () {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
const debounceES6 = (callback, wait, immediate=false) => {
let timeout = null
return (...args) => {
const callNow = immediate && !timeout
const next = () => callback(...args)
clearTimeout(timeout)
timeout = setTimeout(next, wait)
if (callNow) { next() }
}
}
document.querySelector('.es5').addEventListener('click', debounceES5(() => {console.log('clicked')}, 1000, true))
document.querySelector('.es6').addEventListener('click', debounceES6(() => {console.log('clicked')}, 1000, true))
Click both of these buttons fast and see how they react differently
<br />
<button class="es5">ES5</button>
<button class="es6">ES6</button>
答案 0 :(得分:2)
这是您用ES6编写的ES5函数-无需跳过任何详细信息(context
除外)
const debounce = (func, wait, immediate=false) => {
let timeout;
return (...args) => {
const later = () => {
timeout = null; // added this to set same behaviour as ES5
if (!immediate) func(...args); // this is called conditionally, just like in the ES5 version
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func(...args);
};
};
请注意,later
函数的功能与ES5版本完全相同
现在,它的行为(几乎)与ES5版本相同...整个context = this
东西似乎在ES5版本中似乎完全怪异在示例用法中是有意义的
但是,根据注释,由于代码用于事件处理程序,
this
非常重要,因此它是事件目标,因此,您实际上无法返回arrow function
更好的代码是
const debounce = (func, wait, immediate=false) => {
let timeout;
return function (...args) {
const later = () => {
timeout = null; // added this to set same behaviour as ES5
if (!immediate) func.apply(this, args); // this is called conditionally, just like in the ES5 version
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(this, args);
};
};
答案 1 :(得分:1)
您不能在debounce
中使用箭头功能(嗯,您需要知道可以在哪里和不能在哪里)
创建箭头功能 bind this
。这意味着数组中的this
永远也不会改变。
例如
'use strict';
function safeToString(v) {
return v === undefined
? 'undefined'
: v.toString();
}
function regularFunc() {
console.log('regular:', safeToString(this));
}
const arrowFunc = () => {
console.log('arrow:', safeToString(this));
};
regularFunc();
arrowFunc();
regularFunc.call("hello");
arrowFunc.call("world");
在regularFunc
情况下this
的通知未定义,稍后我们可以将其重新定义为hello
,但是在arrowFunc
情况下,通知始终为[Object Window]
所以您的ES6防抖没有。这是应该可以使用的ES6版本
const debounce = (callback, wait, immediate) => {
let timeout;
return (...args) => {
const callNow = immediate && !timeout
const next = () => callback(...args)
clearTimeout(timeout)
timeout = setTimeout(next, wait)
if (callNow) { next() }
}
}
让我们测试一下
function es5Debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
const es6Debounce = (callback, wait, immediate) => {
let timeout;
return (...args) => {
const callNow = immediate && !timeout
const next = () => callback(...args)
clearTimeout(timeout)
timeout = setTimeout(next, wait)
if (callNow) {
next()
}
}
}
function safeToString(v) {
return v === undefined
? 'undefined'
: v.toString();
}
class Test {
constructor(name) {
this.name = name;
}
log(...args) {
console.log(
this ? this.name : 'undefined',
safeToString(this),
...args);
}
}
class ES5Test extends Test {
constructor() {
super('ES5:');
}
}
ES5Test.prototype.log = es5Debounce(ES5Test.prototype.log, 1);
class ES6Test extends Test {
constructor() {
super('ES6:');
}
}
ES6Test.prototype.log = es6Debounce(ES6Test.prototype.log, 1);
const es5Test = new ES5Test();
const es6Test = new ES6Test();
es5Test.log("hello");
es6Test.log("world");
您可以看到es6版本失败,因为this
错误。如果您只使用过非成员函数,那么es6Debounce
似乎可以正常工作,但是一旦您在类或事件处理程序上使用成员函数,您就会发现es6Debounce
不起作用,{{1 }}设置不正确。
此处的代码尝试显示该错误。 this
和ES5Class
是相同的。测试应该打印
ES6Class
代替打印
ES5: [object Object] hello
ES6: [object Object] world
作为另一个示例,让我们尝试一个事件处理程序
ES5: [object Object] hello
undefined undefined world
function es5Debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
const es6Debounce = (callback, wait, immediate) => {
let timeout;
return (...args) => {
const callNow = immediate && !timeout
const next = () => callback(...args)
clearTimeout(timeout)
timeout = setTimeout(next, wait)
if (callNow) {
next()
}
}
}
function mousemove(e) {
console.log(this.id, e.pageX, e.pageY);
}
document.querySelector('#es5')
.addEventListener('mousemove', es5Debounce(mousemove));
document.querySelector('#es6')
.addEventListener('mousemove', es6Debounce(mousemove));
#es5, #es6 {
margin: 1em;
width: 10em;
height: 2em;
display: inline-block;
}
#es5 {
background: orange;
}
#es6 {
background: yellow;
}
将鼠标移到2个区域上。再次注意es6一个错误。
这是否很重要,我不知道,但是您明确发布的原始<div id="es5">es5</div>
<div id="es6">es6</div>
包含使该案例有效的代码。
答案 2 :(得分:1)
我的首选解决方案是选自Chris Boakes'博客文章Understanding how a JavaScript ES6 debounce function works的以下解决方案:
function debounce(callback, wait) {
let timeout;
return (...args) => {
const context = this;
clearTimeout(timeout);
timeout = setTimeout(() => callback.apply(context, args), wait);
};
}
尽管它不提供immediate
arg。仍然可以在这里共享。