概念:
debounce 防抖 、 throttle 节流
节流
节流的原理很简单:
如果你持续触发事件,每隔一段时间,只执行一次事件。
根据首次是否执行以及结束后是否执行,效果有所不同,实现的方式也有所不同。
我们用 leading 代表首次是否执行,trailing 代表结束后是否再执行一次。
关于节流的实现,有两种主流的实现方式,一种是使用时间戳,一种是设置定时器。
使用时间戳:
让我们来看第一种方法:使用时间戳,当触发事件的时候,我们取出当前的时间戳,然后减去之前的时间戳(最一开始值设为 0 ),如果大于设置的时间周期,就执行函数,然后更新时间戳为当前的时间戳,如果小于,就不执行。
———————————————————————————————————————————————————————————————————————
防抖函数分为非立即执行版和立即执行
- 非立即执行
非立即执行版的意思是触发事件后函数不会立即执行,而是在 n 秒后执行,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
function debounce(func, wait) {
let timeout; return function () {
let context = this; let args = arguments; if (timeout) clearTimeout(timeout); timeout = setTimeout(() => {
func.apply(context, args) }, wait); } }
我们依旧使用上述绑定 mousemove 事件的例子,通过上面的防抖函数,我们可以这么使用
content.onmousemove = debounce(count,1000);

可以看到,在触发事件后函数 1 秒后才执行,而如果是在触发事件后的 1 秒内又触发了事件,则会重新计算函数执行时间。
上述防抖函数的代码还需要注意的是 this 和 参数的传递
let context = this; let args = arguments;
防抖函数的代码使用这两行代码来获取 this 和 参数,是为了让 debounce 函数最终返回的函数 this 指向不变以及依旧能接受到 e 参数。
- 立即执行版本
function debounce(func,wait) {
let timeout; return function () {
let context = this; let args = arguments; if (timeout) clearTimeout(timeout); let callNow = !timeout; timeout = setTimeout(() => {
timeout = null; }, wait) if (callNow) func.apply(context, args) } }
立即执行版的意思是触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果。
双剑合璧版:
/ * @desc 函数防抖 * @param func 函数 * @param wait 延迟执行毫秒数 * @param immediate true 表立即执行,false 表非立即执行 */ function debounce(func,wait,immediate) {
let timeout; return function () {
let context = this; let args = arguments; if (timeout) clearTimeout(timeout); if (immediate) {
var callNow = !timeout; timeout = setTimeout(() => {
timeout = null; }, wait) if (callNow) func.apply(context, args) } else {
timeout = setTimeout(function(){
func.apply(context, args) }, wait); } } }
对于节流,一般有两种方式可以实现,分别是时间戳版和定时器版。
时间戳版:
function throttle(func, wait) {
let previous = 0; return function() {
let now = Date.now(); let context = this; let args = arguments; if (now - previous > wait) {
func.apply(context, args); previous = now; } } }
使用方式如下
content.onmousemove = throttle(count,1000);

可以看到,在持续触发事件的过程中,函数会立即执行,并且每 1s 执行一次。
定时器版:
function throttle(func, wait) {
let timeout; return function() {
let context = this; let args = arguments; if (!timeout) {
timeout = setTimeout(() => {
timeout = null; func.apply(context, args) }, wait) } } }
我们应该可以很容易的发现,其实时间戳版和定时器版的节流函数的区别就是,时间戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内结束的时候。
同样地,我们也可以将时间戳版和定时器版的节流函数结合起来,实现双剑合璧版的节流函数。
双剑合璧版:
/ * @desc 函数节流 * @param func 函数 * @param wait 延迟执行毫秒数 * @param type 1 表时间戳版,2 表定时器版 */ function throttle(func, wait ,type) {
if(type===1){
let previous = 0; }else if(type===2){
let timeout; } return function() {
let context = this; let args = arguments; if(type===1){
let now = Date.now(); if (now - previous > wait) {
func.apply(context, args); previous = now; } }else if(type===2){
if (!timeout) {
timeout = setTimeout(() => {
timeout = null; func.apply(context, args) }, wait) } } } }
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/202468.html原文链接:https://javaforall.net
