使用lodash防抖_什么,lodash 的防抖失效了?

d35ab7b06ec1648860f47ab3e403aa78.gif   戳蓝字「前端技术优选」关注我们哦!

作者:yeyan1996

https://juejin.im/post/6892577964458770445

应某人的要求被迫营业,望各位看官不要吝啬手中的赞-。-

背景

在使用 uni-app 开发小程序时,有个填写表单的需求,包含两个输入框,看起来像这样

855327c6d09a1fbb079e4495f0279281.png
image-20201107143814796

两个在普通不过的输入框

因为需要复用一些样式和逻辑,所以将输入框抽象成了组件,代码简化后如下




子组件代码






由于在父组件中需要依赖输入的值请求接口,为避免接口频繁调用,这边引入 lodash debounce 用于防抖

这个需求在 yeyan1996 眼中没有任何难度,但在几天后却收到了部分用户反馈,说在两个输入框分别填写了值,但最终只有一个输入框有效

这时才回头想起代码中的 debounce ....

问题原因

收到用户反馈后,yeyan1996 尝试多次点击输入框,发现问题并不是必现,最终总结出了规律

填写第一个输入框后,快速对第二个输入框进行输入,才会造成最终的表单数据中只有一个值的问题

通过下图子组件的 log 可以看到,虽然 ui 界面显示两个输入框都有值,但实际只触发了第二个输入框的 log

c983b604252e091198af08422cb75fa6.gif
Kapture 2020-11-07 at 14.58.57

之所以 ui 界面显示两个输入框都有值,是因为是用户直接和 textarea 控件交互,实际并没有更新控件绑定的 value 值

最终结论:第一个输入框中被 debounce 包裹的函数并没有执行

是防抖问题么?

尝试将 debounce 去掉后,果然 bug 解决了

99836957fa7ec10ab6ded97c2ce60116.gif
Kapture 2020-11-07 at 15.06.41

那么,是防抖的问题么?

不妨先思考下 Vue 组件的实现原理,我在 [Vue.js进阶]从源码角度剖析Vue的生命周期 中提到过,每个 .vue 文件可以理解为一个构造函数,或者一个 Class,而在父组件中引用组件就等于对其的实例化

  

上述代码即创建了 2 个 CustomTextarea 组件的实例

熟悉面向对象的同学应该知道,构造函数实例化时,同时会创建实例的属性和方法,一般每个实例的属性都不相同,而方法因为是函数,所以会复用,已达到节省内存的效果

class Person {
  constructor(name) {
    this.name = name
  }
  eat() {}
}

const person1 = new Person('张三')
const person2 = new Person('李四')

console.log(person1.name === person2.name) // false
console.log(person1.eat === person2.eat) // true

Vue2  的组件借鉴了面向对象的原理,虽然内部的实现方式不同,但最终的行为一致,即组件的每个实例都拥有不同的 data,但会复用相同的 methods

源码地址:https://github.com/vuejs/vue/blob/dev/src/core/instance/state.js#L286

0468621571a122f5b0a3c8e78b927288.png
image-20201107155528333

286 行中 methods 对象是每个组件实例共用的,每实例化一个组件,会创建相同的引用,指向 methods 中的函数

6725f0954d6040d29fece4ecb112c07f.png
未命名

上图案例中, 所有 custom-textarea 中的 handleInput 都指向同一个函数,而作为 props 的 value 字段是通过父组件传入的,并不会共享(分别为 text1/text2)

解决方案

经过上述的分析,答案显而易见,两个组件实例都指向了同一个被 debounce 包裹的 handleInput 函数

所以在输入第一个值后, 1000 毫秒内快速切换到第二个输入框进行输入,此时由于防抖效果仍存在,导致第一次的输入并没有计算在内

而第二次输入完毕后,经过 1000 毫秒,最终只会执行第二个 custom-textarea 的 handleInput

只要使得每个组件实例的 handleInput 互相独立,即可解决问题






将 handleInput 从 methods 放到 data 中,每次初始化时创建防抖函数,此时每个组件实例的 handleInput 就不会互相干扰

fdb5a4a3928c2825d2dc574d96aeaa7c.gif
Kapture 2020-11-07 at 16.44.41

大功告成???

题外话

Vue 组件中通过将 data 定义为一个函数,函数的返回值作为组件的数据来源,使得每个组件实例的数据都不相同

而 Vue 组件中 methods 是所有实例共用的,那么对于 watch/computed/生命周期,它们是否会共用的呢?




和 methods 对象相同,computed 对象的属性名是一个响应式变量,而值是一个函数,所以所有实例也会指向同一个函数,但由于这个函数需要有返回值,所以不会用防抖函数进行包裹,很少遇到函数公用导致的问题

而 watch 也和 methods 对象相同,所有组件实例共用,所以也会存在防抖的问题

至于生命周期本身就是一个函数,如果对生命周期设置了防抖,多个组件实例同时初始化时也会造成只执行一次的情况

参考资料

[Vue.js进阶]从源码角度剖析Vue的生命周期

【Vue原理】Methods - 源码版](https://segmentfault.com/a/1190000019605909)

a8e91c1a28d4f5a1192fe83fa2526be5.gif

1b8bc32c237f7ebde3bc693feb825fac.pngafcfcf63af2a65377fa70e382eb75c50.png在看点这里8fb8e76c89a4b3a2e2a50bda355ff669.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/279264.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu 12.10中的8个新功能,Quantal Quetzal

Ubuntu 12.10 has been released and you can download it now. From better integration with web apps and online services to improvements in Unity, there are quite a few changes – although none of them are huge or groundbreaking. Ubuntu 12.10已发布&#xff0c…

背单词APP调研分析

前言:随着我国网络经济重心向移动端的转移,移动教育领域获得的关注度在持续放大。互联网的发展和移动设备的普及,我们开始在移动设备上学习,各种学习教育软件如雨后春笋,越来越多,就背单词软件来说&#xf…

linux 提取cpio_Linux提取RPM包文件(cpio命令)详解

在讲解如何从 RPM 包中提取文件之前,先来系统学习一下 cpio 命令。cpio 命令用于从归档包中存入和读取文件,换句话说,cpio 命令可以从归档包中提取文件(或目录),也可以将文件(或目录)复制到归档包中。归档包,也可称为文…

cdh中使用hue使用教程_我可以在户外使用Philips Hue灯泡吗?

cdh中使用hue使用教程Philips Hue lights are great to have in your house, and they can add a lot of convenience to your living space. However, what if you want to use these smart bulbs outdoors in porch lights or flood lights? Will Philips Hue bulbs work pr…

django (三) admin后台系统

admin后台系统 1. 安装MySQL 1,安装mysql: sudo apt install mysql-server (安装过程中输入密码并牢记) 2,安装后进入mysql: mysql -u用户名 -p密码 mysql -uroot -proot ​ 3,在Django中配置和使用mysql数据库 使用mysql数据库,settings中配置如下: DAT…

python博客访问量_史诗级干货-python爬虫之增加CSDN访问量

AI人工智能史诗级干货-python爬虫之增加CSDN访问量史诗级干货-python爬虫之增加CSDN访问量搜索微信公众号:‘AI-ming3526’或者’计算机视觉这件小事’ 获取更多算法、机器学习干货csdn:https://blog.csdn.net/baidu_31657889/github:https://github.com…

弄断过河电缆_你说的是:剪断电缆线

弄断过河电缆Earlier this week we asked you if you’d cut the cable and switched to alternate media sources to get your movie and TV fix. You responded and we’re back with a What You Said roundup. 本周早些时候,我们问您是否要切断电缆并切换到其他媒…

复制粘贴的句子

Today you do things people will not do,tomorrow you will do things people can not do. 你今天做别人不愿做的事,明天就能做别人做不到的事。转载于:https://www.cnblogs.com/wensens/p/9723998.html

路由销毁上一页_路由器原理(数据通信)

路由:对数据包选择路径的过程路由器(也叫网关)智能选择数据传输路由的设备,其端口数量较少!功能:连接网络1.连接异构网络以太网、ATM网络、FDDI网络2.连接远程网络局域网、广域网隔离广播将广播隔离在局域网内路由选择网络安全地址…

您可能没有使用的最佳三星Galaxy功能

Samsung packs its flagship phones with a slew of features—some are even better than stock Android. Either way, there are a lot of things on these phones that you may not be using. Here are some of the best. 包三星旗舰手机用的特性-摆有的甚至比普通的Android…

win7更新错误0x800b0109_win7更新漏洞后产生0x0000006B蓝屏的解决方法图解

这几天不少网友在使用win7更新补丁后就蓝屏了,代码为0x0000006b。发生这一蓝屏问题的都是安装了2016年四月份推出的安全更新补丁,安装后就出现蓝屏,有的网友表示没问题,有的直接蓝了。这个蓝屏重启后依旧,安全模式进不…

获取构造器的信息

获取类构造器的用法与上述获取方法的用法类似,如: import java.lang.reflect.*;public class constructor1 {public constructor1() {}protected constructor1(int i, double d) { } public static void main(String args[]) { try { Class cls Class.f…

如何使用facebook_如果每个人都已经开始使用Facebook,Facebook能否继续发展?

如何使用facebookThere are only so many people on earth, and so many hours in the day. Is that starting to limit the growth of social media? 地球上只有那么多人,一天中有很多小时。 这是否开始限制社交媒体的增长? Think about how much time…

2018-10-03-Python全栈开发-day60-django序列化-part3

联合唯一 clean_字段方法只能对某个字段进行检查,当clean方法执行完之后,最后还会执行clean方法,在clean方法中,可以通过获取数据字典中的值然后进行验证 from django.shortcuts import render,HttpResponsefrom django import fo…

mysql时间字段条件查询_mysql 查询 时间作为查询条件

今天select * from 表名 where to_days(时间字段名) to_days(now());昨天SELECT * FROM 表名 WHERE TO_DAYS( NOW( ) ) - TO_DAYS( 时间字段名) < 1近7天SELECT * FROM 表名 where DATE_SUB(CURDATE(), INTERVAL 7 DAY) < date(时间字段名)近30天SELECT * FROM 表名 whe…

mac按文件名查找文件_如何在Mac上查找和删除大文件

mac按文件名查找文件Freeing up disk space on a full hard drive can be difficult, especially when it’s full of small files. However, there are some excellent tools for macOS that let you find the files taking up the most space and delete the ones you don’t…

Swift5.1 语言参考(十) 语法汇总

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号&#xff1a;山青咏芝&#xff08;shanqingyongzhi&#xff09;➤博客园地址&#xff1a;山青咏芝&#xff08;https://www.cnblogs.com/strengthen/&#xff09;➤GitHub地址&a…

timestamp mysql php_PHP和Mysql的Timestamp互换

在mysql中有三种时间字段类型&#xff1a;DATETIME&#xff0c;DATE和TIMESTAMP。DATETIME以YYYY-MM-DD HH:MM:SS格式的字符串来保存数据&#xff1b;DATE则是只有年月日以YYYY-MM-DD形式的字串&#xff1b;TIMESTAMP类型和PHP中的TIMESTAMP类型名字一样&#xff0c;但是两者基…

dmg是什么文件格式_什么是DMG文件(以及我该如何使用)?

dmg是什么文件格式DMG files are containers for apps in macOS. You open them, drag the app to your Applications folder, and then eject them, saving you the hassle of the dreaded “Install Wizard” of most Windows apps. So if all they are is a folder for an a…

mysql索引三个字段查询两个字段_mysql中关于关联索引的问题——对a,b,c三个字段建立联合索引,那么查询时使用其中的2个作为查询条件,是否还会走索引?...

情况描述&#xff1a;在MySQL的user表中&#xff0c;对a,b,c三个字段建立联合索引&#xff0c;那么查询时使用其中的2个作为查询条件&#xff0c;是否还会走索引&#xff1f;根据查询字段的位置不同来决定&#xff0c;如查询a, a,b a,b,c a,c 都可以走索引的&#…