该篇文章借鉴了一下博文
https://www.jianshu.com/p/d8c3bfe10754
https://zhuanlan.zhihu.com/p/88799841
如果不想用大佬的轮子,自己写一套也可以,请查看这篇博客JavaScript防抖和节流–造轮子它不香吗
import React, { Component } from 'react';
import { throttle, debounce } from 'throttle-debounce';//1.引入throttle
export default class Children extends Component {
constructor(props) {
super(props);
/**
* 2.把经过节流处理的函数赋值给组件中的函数
* @param {number} 2000 是等待时间
*/
this.onClick = throttle(2000, this.onClick);
this.state = {
}
}
render() {
return (
<div>
<button onClick={this.onClick}>确定</button>
</div>
)
}
onClick = (e) => {
console.log('e', e);
}
}
上面是react开发大佬封装的方法,使用起来超级方便,只要两步
throttle
接下来,艾瑞宝迪,一起去看看源码是如何实现的,看完之后,我们自己也可以造轮子
上面的引入方法是react16.8
版本的,低版本16.3
修改了引用方法
import throttle from 'lodash/throttle';
this.onClick = throttle(this.onClick, 2000);
不过此功能向下兼容,老方法在新版本中也可以使用。
下面我们基于新版本源码进行分析
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
上面两行,使用严格模式
设置导出模块的方式(这块我不太懂,猜这个意思是设置一下导出的方式,查了部分资料还没有结果,等我弄明白了回来补充)
index.cjs.js
也就是通过babel转化过后的commonJS
代码。给模块的输出对象增加__esModule
是为了将不符合 Babel 要求的 CommonJS 模块转换成符合要求的模块,这一点在require
的时候体现出来。如果加载模块之后,发现加载的模块带着一个 __esModule
属性,Babel 就知道这个模块肯定是它转换过的,这样 Babel 就可以放心地从加载的模块中调用 exports.default
这个导出的对象,也就是 ES6 规定的默认导出对象,所以这个模块既符合 CommonJS 标准,又符合 Babel 对 ES6 模块化的需求。然而如果__esModule
不存在,也没关系,Babel 在加载了一个检测不到 __esModule
的模块时,它就知道这个模块虽然符合 CommonJS 标准,但可能是一个第三方的模块,Babel 没有转换过它,如果以后直接调用exports.default
是会出错的,所以现在就给它补上一个default
属性,就干脆让 default
属性指向它自己就好了,这样以后就不会出错了。
该解释源自分析 Babel 转换 ES6 module 的原理一文,也感谢多位前辈给予的帮助
节流函数的执行,特别适用于速率限制,比如“resize”,“scroll”这样的事件执行处理程序
/**
* @param {Number} delay
* @param {Boolean} [noTrailing]
* @param {Function} callback
* @param {Boolean} [debounceMode]
* @return {Function} A new, throttled, function.
*/
delay : number类型 以毫秒为单位的0或者更大的数字, 对于事件回调,数值100或250(甚至更高)最有用。
[noTrailing] : 布尔类型 []表示可选参数,默认为false,如果设置为true,回调将会先延迟‘delay’毫秒,然后
再调用,如果noTrailing设置为false或者未指定,回调将会在最后一次节流函数执行后,
执行最后一次(在“delay”毫秒内未调用节流函数,内部定时器重置)
callback : 函数类型 延迟“delay”毫秒后执行的函数,this上下文和所有参数将按原样传递,执行限制函数时
返回“callBack”
[debounceMode]: 布尔类型 如果“debounceMode”一开始是true,在延迟“delay”毫秒后安排“clear”执行,如果
“debounceMode”结束的时候是false,在延迟“delay”毫秒后安排“callBack”执行。
返回值: 函数类型 一个新的节流函数
function throttle (delay, noTrailing, callback, debounceMode) {
/*
* After wrapper has stopped being called, this timeout ensures that
* `callback` is executed at the proper times in `throttle` and `end`
* debounce modes.
*/
在包装器停止调用后,此定时器确保在适当的时间,节流和结束防抖模式中被执行
var timeoutID;
var cancelled = false; // 记录回调上次记录时间
var lastExec = 0; // 清除现有定时器函数
function clearExistingTimeout() {
if (timeoutID) {
clearTimeout(timeoutID);
}
} // 取消下一个exec函数
function cancel() {
clearExistingTimeout();
cancelled = true;
} // 清除退出超时,设置取消
if (typeof noTrailing !== 'boolean') {
debounceMode = callback;
callback = noTrailing;
noTrailing = undefined;
}
//包装器函数封装了所有节流/防抖功能,执行的时候会限制回调函数的执行速率
function wrapper() {
var self = this;
var elapsed = Date.now() - lastExec;
var args = arguments;
if (cancelled) {
return;
} // 执行回调,更新lastExec时间戳
function exec() {
lastExec = Date.now();
callback.apply(self, args);
}
//如果防抖模式在开始的时候设置为true,此函数用来清理标志来保证以后回调函数的执行
function clear() {
timeoutID = undefined;
}
if (debounceMode && !timeoutID) {
//如果是防抖模式,并且首次执行,执行回调
exec();
}
clearExistingTimeout();
if (debounceMode === undefined && elapsed > delay) {
//在节流模式中,如果超过延迟时间,执行回调函数
exec();
} else if (noTrailing !== true) {
/*
*在后执行节流模式中,延迟时间没有超出时,安排回调在最近一次执行后执行延迟毫秒
*如果一开始是防抖模式,在延迟’delay‘毫秒后执行’clear‘
*如果最后防抖模式是false,在延迟’delay‘毫秒后执行回调
*/
timeoutID = setTimeout(debounceMode ? clear : exec, debounceMode === undefined ? delay - elapsed : delay);
}
}
wrapper.cancel = cancel; // 返回包装器函数
return wrapper;
}
/**
*
* @param {Number} delay
* @param {Boolean} [atBegin]
* @param {Function} callback
* @return {Function} A new, debounced function.
*/
函数的防抖执行,防抖不同于节流,确保函数只执行一次,无论是在一系列调用的最开始或是最后
delay: 类型数字 一个零或更高延迟毫秒,对于事件回调,数值大约100或250(甚至更高)时最有效
atBegin: 布尔类型 可选,默认false,如果atBegin是false或者未指定,仅在上次取消声明的函数调用
后的“delay”毫秒执行回调,如果atBegin是true,回调只会在第一次防抖函数执行
后执行(在“delay”毫秒后节流函数没有执行的话,计时器重置)
callback: 函数类型 要在延迟毫秒后执行的函数。“this”上下文和所有参数在执行取消声明的函数时按原
样传递给“callback”。
function debounce (delay, atBegin, callback) {
return callback === undefined ? throttle(delay, atBegin, false) : throttle(delay, callback, atBegin !== false);
}
exports.throttle = throttle;
exports.debounce = debounce;
本文是我第一次认认真真仔仔细细的,研究每一行源码,用自己造的轮子对比大佬的,要学的还有很多,文中很多解释不到位,说明有误的地方,希望各位前辈多多指点。