We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
js的典型的场景
这些事件会频繁触发会影响性能,如果使用节流,降低频次,保留了用户体验,又提升了执行速度,节省资源。
节流的原理:持续触发某事件,每隔一段时间,只执行一次。
通俗点说,3 秒内多次调用函数,但是在 3 秒间隔内只执行一次,第一次执行后 3 秒 无视后面所有的函数调用请求,也不会延长时间间隔。3 秒间隔结束后则开始执行新的函数调用请求,然后在这新的 3 秒内依旧无视后面所有的函数调用请求,以此类推。
简单来说:每隔单位时间( 3 秒),只执行一次。
目前比较主流的实现方式有两种:时间戳、定时器。
使用时间戳实现:首先初始化执行事件的时间previous为0,然后将当前的时间戳减去上次执行时间(now - previous),如果大于wait,则直接执行函数,并且将此时的执行时间now赋给previous(previous = now)。
由于首次previous = 0,则此时函数第一次触发就会立即执行。
后续则每隔wait时间执行一次,如果停止触发,则不会再执行函数。
// 由于一开始now - 0 > wait,则这个写法,时间会立即执行,没过一秒会执行一次,停止触发,则不会再执行事件 function throttle(func, wait = 500) { let context, now; let previous = 0; // 设置过去的执行时间初始值为0 return function (...args) { context = this; now = +(Date.now() || new Date().getTime()); if (now - previous > wait) { func.apply(context, args); previous = now; } }; }
使用定时器实现:首先初始化timeout,然后定义!timeout为true的情况下,直接执行setTimeout,,等待wait时间后执行函数,然后清空timeout,以此类推,重新进入也会按上述执行。
由于进入函数,就执行setTimeout,所以不会立即触发函数执行。
后续则每隔wait时间执行一次,如果停止触发,而后还会触发执行一次函数。
// 由于一进入就创建了定时器,所以不会立即触发函数执行 function throttle(func, wait = 500) { let context, timeout; return function (...args) { context = this; if (!timeout) { timeout = setTimeout(function () { timeout = null; func.apply(context, args); }, wait); } }; }
如果,我们需要既刚开始就立即执行,停止触发后,还会触发执行一次函数。
下面,我们将定时器和时间戳合并,组成一个全新的节流版本。
function throttle(func, wait = 500) { let context, timeout, result; let previous = 0; const throttled = function (...args) { context = this; const now = +(Date.now() || new Date().getTime()); // 当前时间 // 下次触发 func 剩余时间 const remaining = wait - (now - previous); // 如果没有剩余时间或者改了系统时间,这时候不需要等待,直接立即执行,这样就会第一次就执行 if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; func.apply(context, args); } else if (!timeout) { // 剩余的情况就是remaining<=wait的情况,这里使用setTimeout就可以最后也会执行一次 timeout = setTimeout(function () { timeout = null; previous = +(Date.now() || new Date().getTime()); // 这里是将previous重新赋值当前时间 func.apply(context, args); }, remaining); } }; return throttled; }
由于合并后的版本并没用返回值的优化+取消功能。
下面对代码进行返回值+取消功能优化:
function throttle(func, wait = 500) { let context, timeout, result; let previous = 0; const showResult = function (e1, e2) { result = func.apply(e1, e2); return result; }; const throttled = function (...args) { context = this; const now = +(Date.now() || new Date().getTime()); // 当前时间 // 下次触发 func 剩余时间 const remaining = wait - (now - previous); // 如果没有剩余时间或者改了系统时间,这时候不需要等待,直接立即执行,这样就会第一次就执行 if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; return showResult(context, args); } else if (!timeout) { // 剩余的情况就是remaining<=wait的情况,这里使用setTimeout就可以最后也会执行一次 timeout = setTimeout(function () { timeout = null; previous = +(Date.now() || new Date().getTime()); // 这里是将previous重新赋值当前时间 return showResult(context, args); }, remaining); } retrun result }; throttled.cancel = function () { if (timeout !== undefined) { clearTimeout(timeout); } previous = 0; context = timeout = result = undefined; }; return throttled; }
有时候,我们也希望无头有尾,或者有头无尾。
function throttle(func, wait = 500, options = {}) { let context, timeout, result; let previous = 0; // 如果同时设置无头无尾,则直接使用默认设置,其他情况,则走下述操作 if (!(options.leading === false && options.trailing === false)) { leading = !!options.leading; // 默认去除立即执行部分 trailing = "trailing" in options ? !!options.trailing : true; // 默认保留尾部 } // 返回原函数的return const showResult = function (e1, e2) { result = func.apply(e1, e2); return result; }; // 获取当前时间 const getNow = function () { return +(Date.now() || new Date().getTime()); }; const throttled = function (...args) { context = this; const now = getNow(); // 当前时间 // 下次触发 func 剩余时间 if (!previous && leading === false) previous = now; const remaining = wait - (now - previous); // 如果没有剩余时间或者改了系统时间,这时候不需要等待,直接立即执行,这样就会第一次就执行 if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; return showResult(context, args); } else if (!timeout && trailing !== false) { // 剩余的情况就是remaining<=wait的情况,这里使用setTimeout就可以最后也会执行一次 timeout = setTimeout(function () { timeout = null; previous = options.leading === false ? 0 : getNow(); // 这里是将previous重新赋值当前时间 return showResult(context, args); }, remaining); } return result; }; throttled.cancel = function () { if (timeout !== undefined) { clearTimeout(timeout); } previous = 0; context = timeout = result = undefined; }; return throttled; }
这里,如果options不传参数,函数默认设置
let leading = false let trailing = true
也就是无头有尾。
如果同时设置无头无尾,则会直接采用默认设置,无头有尾。
// 如果同时设置无头无尾,则直接使用默认设置,其他情况,则走下述操作 if (!(options.leading === false && options.trailing === false)) { leading = !!options.leading; // 默认去除立即执行部分 trailing = "trailing" in options ? !!options.trailing : true; // 默认保留尾部 }
可以去Github仓库查看演示代码
主要是日常对每个进阶知识点的摸透,跟着大佬一起去深入了解JavaScript的语言艺术。
后续会一直更新,希望各位看官不要吝啬手中的赞。
❤️ 感谢各位的支持!!!
❤️ 如果有错误或者不严谨的地方,请务必给予指正,十分感谢!!!
❤️ 喜欢或者有所启发,欢迎 star!!!
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
js的典型的场景
...
这些事件会频繁触发会影响性能,如果使用节流,降低频次,保留了用户体验,又提升了执行速度,节省资源。
原理
通俗点说,3 秒内多次调用函数,但是在 3 秒间隔内只执行一次,第一次执行后 3 秒 无视后面所有的函数调用请求,也不会延长时间间隔。3 秒间隔结束后则开始执行新的函数调用请求,然后在这新的 3 秒内依旧无视后面所有的函数调用请求,以此类推。
简单来说:每隔单位时间( 3 秒),只执行一次。
实现方式
目前比较主流的实现方式有两种:时间戳、定时器。
时间戳实现
使用时间戳实现:首先初始化执行事件的时间previous为0,然后将当前的时间戳减去上次执行时间(now - previous),如果大于wait,则直接执行函数,并且将此时的执行时间now赋给previous(previous = now)。
由于首次previous = 0,则此时函数第一次触发就会立即执行。
后续则每隔wait时间执行一次,如果停止触发,则不会再执行函数。
定时器实现
使用定时器实现:首先初始化timeout,然后定义!timeout为true的情况下,直接执行setTimeout,,等待wait时间后执行函数,然后清空timeout,以此类推,重新进入也会按上述执行。
由于进入函数,就执行setTimeout,所以不会立即触发函数执行。
后续则每隔wait时间执行一次,如果停止触发,而后还会触发执行一次函数。
合并版本
如果,我们需要既刚开始就立即执行,停止触发后,还会触发执行一次函数。
下面,我们将定时器和时间戳合并,组成一个全新的节流版本。
合并版本优化
由于合并后的版本并没用返回值的优化+取消功能。
下面对代码进行返回值+取消功能优化:
功能性优化
有时候,我们也希望无头有尾,或者有头无尾。
这里,如果options不传参数,函数默认设置
也就是无头有尾。
如果同时设置无头无尾,则会直接采用默认设置,无头有尾。
演示地址
可以去Github仓库查看演示代码
跟着大佬学系列
主要是日常对每个进阶知识点的摸透,跟着大佬一起去深入了解JavaScript的语言艺术。
后续会一直更新,希望各位看官不要吝啬手中的赞。
❤️ 感谢各位的支持!!!
❤️ 如果有错误或者不严谨的地方,请务必给予指正,十分感谢!!!
❤️ 喜欢或者有所启发,欢迎 star!!!
参考
The text was updated successfully, but these errors were encountered: