### 简单了解
*****
* 防抖节流我相信大家都不陌生,简单理解,可有效的规避很多重复性(误)操作。
* 防抖:在规定时间内,操作时长间接性小于规定时间,只执行第一次或者最后一次;如:500ms执行一次,间接时间为100ms,一共操作时长2000ms,则会执行**1**次。
* 节流:规定时间内执行一次,操作时长大于规定时间,则开启下一个执行;如:500ms执行一次,一共操作时长2000ms,则会执行**4**次。
### 问题所在
*****
问题:`clearTimeout(timeout)`后,`timeout=???`、以及定时器有什么变化?
先简单过一下 下面的代码,平淡无奇哈,但是关键在于这句 `timeout && clearTimeout(timeout)`,试想经过`clearTimeout(timeout)`后,`timeout=???`,等于`null`吗?可以看到清除定时器后timeout的值并非null,而且还不变,这是不是有点匪夷所思啊?
* 接下来我们分析一下,我们开启一个定时器,并且把这个定时器记录赋给一个变量,这时候定时器在内存中,可以通过该变量对应id去查找到,经过`clearTimeout(timeout)`后,只是对内存中的定时器进行清除,仅此而已,并未对变量进行修改操作;
* 如果我们直接进行`timeout=null`,而没有`clearTimeout(timeout)`,那么定时器是没有清除的,只是把timeout指向变了,并没有清除掉定时器,此时定时器在内存中虽然没有变量指向它,但它仍存在内存中,待wait时间一到,就执行callback函数。
![](https://img.kancloud.cn/18/48/18482e9ae34e5e10670195f00d26c19f_630x259.png)
### 防抖函数实现
```
/**
* 防抖函数:多次触发事件,事件处理函数只执行一次,并且在触发操作后执行。
* 原理:利用闭包原理,就是函数需要在刚完成时需要被使用,赋值给一个变量,由这个变量去使用。
* @param {*} callback 回调函数
* @param {*} wait 延迟时间,默认500ms
* @param {*} immediate 是否立即执行,默认是
*/
export const debounce = (callback, wait = 500, immediate = true) => {
let timeout = null;
let debounced = function() {
let self = this;
timeout && clearTimeout(timeout);
if (immediate) {
let callNow = !timeout;
if (callNow) callback.apply(self, arguments);
timeout = setTimeout(() => {
timeout = null;
}, wait);
} else {
timeout = setTimeout(() => {
callback.apply(self, arguments);
}, wait);
}
};
debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
};
return debounced;
};
```
### 节流函数实现
顺便附上节流函数
```
/**
* 节流函数:触发操作后,在间隔连续时间内只执行一次,过了规定间隔时间后,才进行下一次调用
* 原理:对函数进行间隔操作,在规定间隔时间内,如有重复操作,则清除掉本次操作
* @param {*} callback
* @param {*} wait 间隔时间,默认500ms
* @param {*} options = { leading: false, // 禁用第一次执行 trailing: false // 禁用停止触发的回调 }
* @returns
*/
export const throttle = (callback, wait = 500, options = {}) => {
let time, context, args;
let previous = 0;
let later = function() {
previous = options.leading === false ? 0 : new Date().getTime();
time = null;
callback.apply(context, args);
if (!time) context = args = null;
};
let throttled = function() {
let now = new Date().getTime();
if (!previous && options.leading === false) previous = now;
let remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (time) {
clearTimeout(time);
time = null;
}
previous = now;
callback.apply(context, args);
if (!time) context = args = null;
} else if (!time && options.trailing !== false) {
time = setTimeout(later, remaining);
}
};
throttled.cancel = function() {
clearTimeout(time);
time = null;
previous = 0;
};
return throttled;
};
```
- 首页
- 2021年
- 基础知识
- 同源策略
- 跨域
- css
- less
- scss
- reset
- 超出文本显示省略号
- 默认滚动条
- 清除浮动
- line-height与vertical-align
- box-sizing
- 动画
- 布局
- JavaScript
- 设计模式
- 深浅拷贝
- 排序
- canvas
- 防抖节流
- 获取屏幕/可视区域宽高
- 正则
- 重绘重排
- rem换算
- 手写算法
- apply、call和bind原理与实现
- this的理解-普通函数、箭头函数
- node
- nodejs
- express
- koa
- egg
- 基于nodeJS的全栈项目
- 小程序
- 常见问题
- ec-canvas之横竖屏切换重绘
- 公众号后台基本配置
- 小程序发布协议更新
- 小程序引入iconfont字体
- Uni-app
- 环境搭建
- 项目搭建
- 数据库
- MySQL数据库安装
- 数据库图形化界面常用命令行
- cmd命令行操作数据库
- Redis安装
- APP
- 控制缩放meta
- GIT
- 常用命令
- vsCode
- 常用插件
- Ajax
- axios-services
- 文章
- 如何让代码更加优雅
- 虚拟滚动
- 网站收藏
- 防抖节流之定时器清除问题
- 号称破解全网会员的脚本
- 资料笔记
- 资料笔记2
- 公司面试题
- 服务器相关
- 前端自动化部署-jenkins
- nginx.conf配置
- https添加证书
- shell基本命令
- 微型ssh-deploy前端部署插件
- webpack
- 深入理解loader
- 深入理解plugin
- webpack注意事项
- vite和webpack区别
- React
- react+antd搭建
- Vue
- vue-cli
- vue.config.js
- 面板分割左右拖动
- vvmily-admin-template
- v-if与v-for那个优先级高?
- 下载excel
- 导入excel
- Echart-China-Map
- vue-xlsx(解析excel)
- 给elementUI的el-table添加骨架
- cdn引入配置
- Vue2.x之defineProperty应用
- 彻底弄懂diff算法的key作用
- 复制模板内容
- 表格操作按钮太多
- element常用组件二次封装
- Vue3.x
- Vue3快速上手(第一天)
- Vue3.x快速上手(第二天)
- Vue3.x快速上手(第三天)
- vue3+element-plus搭建项目
- vue3
- 脚手架
- vvmily-cli
- TS
- ts笔记
- common
- Date
- utils
- axios封装
- 2022年
- HTML
- CSS基础
- JavaScript 基础
- 前端框架Vue
- 计算机网络
- 浏览器相关
- 性能优化
- js手写代码
- 前端安全
- 前端算法
- 前端构建与编译
- 操作系统
- Node.js
- 一些开放问题、智力题