最近撸React的代码时踩了个关于事件处理的坑,场景如下:在监听某个元素上会频繁触发的事件时,我们往往会对该事件的回调函数进行防抖的处理;防抖的包装函数大致长这样:

debounce = (fn, delay) => {
let timer: any = null;
return function(...args) {
if(timer) {
clearTimeout(timer);
}
timer = setTimeout(fn, delay, ...args);
}
}

核心部分就是用setTimeout()做延时执行,而问题就是出在这里。先说下结论,在React中如果要在异步操作中访问事件对象,则需要先在该事件对象上执行event.persist()。否则的话,在异步操作中访问事件对象时你会发现这个对象上大部分属性都是无效的了。

之前在项目中其他地方也见过这个方法也查了下知道这个东西,不过当时也只是知道有这么个方法并不太理解这么个方法存在的意义,现在好了,踩坑了吧,只好专门去了解下其中的缘由(=_=) 。 异步访问事件对象时其属性失效的原因在于事件派发并处理完后 这个对象不会马上被释放,而是将这个事件对象上的一些属性释放再回收放进被称为“事件池”的这么个地方。 看下react-dom中的这段源码:



在上面步骤中,派发完事件后,会判断事件对象event.isPersistent() 即是否有被持久化;而如果我没有在处理函数中执行过event.persist(),所以就进入了分支执行release操作;执行完release后,这个event上的大部分属性就都被清空了然后被放进事件池里。而异步操作是发生在这个过程之后的,这时候如果要访问该event的话 例如我们获取event.target 这时event上的target属性是不存在的了,代码就出错了。

然后再说下事件池;官方文档在说明上述问题时提到了下事件池

SyntheticEvent 是合并而来。这意味着 SyntheticEvent 对象可能会被重用,而且在事件回调函数被调用后,所有的属性都会无效。出于性能考虑,你不能通过异步访问事件。

说的比较笼统,解释一下:所有产生的事件都会生成一个事件对象,按正常逻辑 在我们的事件处理函数执行完后,这个事件对象就应该被释放了,等待着被内存回收;但如果在短时间内触发了许多次事件,就要频繁的生成和销毁事件对象;那么 为了提高性能,React就用了一个“事件池”这么一个池子,被使用完后的事件,并不直接销毁,而是将其身上的属性清空掉了后放进事件池中, 等到了下一次有同类型事件发生时,就不用再new一个新的事件对象了,直接从事件池取出一个现成的就可以用了, 从而实现事件对象的重用

使用这么一套机制最根本的动机在于:在很多业务系统中创建和销毁对象的代价是非常昂贵的。只接触过前端领域的同学可能没怎么听说过XXX对象池这种概念,不过在其他工种的圈子中这个模式被运用在很多地方, 例如后端中经常提及的线程池、数据库连接池,在游戏引擎Unity中也有对象池的概念。 这个模式对于一些场景的性能提升是非常大的,我们想象一下这些场景:Web服务器遇到高并发时,会在瞬时创建和销毁大量的线程、 又或者当我们在愉快地玩耍诸如FPS类型的游戏时,每个弹药都是一个游戏中的对象,那么就会经常会产生大量的对象,并且在短时间内这些对象又会在使用完后等效被销毁,势必就会给游戏的运行带来很大负担;而且很可能还会伴随着长时间的GC,这样的游戏体验可想而知。

关于在异步操作中访问React事件对象的小问题的更多相关文章

  1. React 事件对象、键盘事件、表单事件、ref获取dom节点、react实现类似Vue双向数据绑定

    1.案例实现代码 import React, { Component } from 'react'; /** * 事件对象.键盘事件.表单事件.ref获取dom节点.react实现类似Vue双向数据绑 ...

  2. JavaScript事件---事件对象

    发文不易,若转载传播,请亲注明出处,谢谢!   内容提纲: 1.事件对象 2.鼠标事件 3.键盘事件 4.W3C与IE JavaScript事件的一个重要方面是它们拥有一些相对一致的特点,可以给你的开 ...

  3. (转)内核线程对象--Event事件对象

    在所有的内核对象中,事件内核对象是个最基本的对象.事件能够通知一个操作已经完成. 客户机和一个服务器,它们之间需要互相进行通信例子(vs2008 ) 事件内核对象的组成 一个使用计数(与所有内核对象一 ...

  4. jquery的click事件对象试解

    在写这篇文档的时候,我并没有深入的去了解jquery的事件对象是什么样的构造,不过以我以往的经验,相信能说道说道,并且可能有百分之八十是正确的,所以我并不建议这篇文档具备一定的权威性,不过可以当成饭后 ...

  5. 第一百二十节,JavaScript事件对象

    JavaScript事件对象 学习要点: 1.事件对象 2.鼠标事件 3.键盘事件 4.W3C与IE JavaScript事件的一个重要方面是它们拥有一些相对一致的特点,可以给你的开发提供更多的强大功 ...

  6. JavaScript(第二十四天)【事件对象】

    JavaScript事件的一个重要方面是它们拥有一些相对一致的特点,可以给你的开发提供更多的强大功能.最方便和强大的就是事件对象,他们可以帮你处理鼠标事件和键盘敲击方面的情况,此外还可以修改一般事件的 ...

  7. node源码详解(七) —— 文件异步io、线程池【互斥锁、条件变量、管道、事件对象】

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource7 本博客同步在https://cnodejs.o ...

  8. React对比Vue(03 事件的对比,传递参数对比,事件对象,ref获取DOM节点,表单事件,键盘事件,约束非约束组件等)

    import React from 'react'; class Baby extends React.Component { constructor (props) { super(props) t ...

  9. react事件中的事件对象和常见事件

    不管是在原生的js还是vue中,所有的事件都有其事件对象,该事件对象event中包含着所有与事件相关的信息,在react中,所有的事件也有其事件对象,在触发DOM上的某个事件时,就会产生一个事件对象. ...

随机推荐

  1. C#LeetCode刷题之#674-最长连续递增序列( Longest Continuous Increasing Subsequence)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3734 访问. 给定一个未经排序的整数数组,找到最长且连续的的递增 ...

  2. 2、java数据类型转换

    当数据类型不一样时,将会发生数据类型转换. 1.自动类型转换(隐式) 1. 特点:代码不需要进行特殊处理,自动完成. 2. 规则:数据范围从小到大. System.out.println(1024); ...

  3. 【SDOI2009】 HH的项链 - 莫队

    题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不断地收集新的贝壳,因此,他的项链变得越来越长. ...

  4. Mybatis-plus 实体类新增属性,使用实体类执行sql操作时忽略该属性 注解

    @TableField(exist = false) 注解加载bean属性上,表示当前属性不是数据库的字段,但在项目中必须使用,这样在新增等使用bean的时候,mybatis-plus就会忽略这个,不 ...

  5. DDD与Repository

    Repository已经不是什么新鲜概念了.DDD模型自2004年提出,发展至今已经16年了.但是不少企业却无法实施,其原因也很简单:DDD是基于需求的,而很多并不理解需求:DDD是容易实现的,而很多 ...

  6. 免费验证码接收网站&不停开小号方法

    手机号注册:免费验证码接收网站 0.http://getfreesmsnumber.com/ 9个外国网站,访问后要快点点击链接,否则2秒会检测出adblocker 1.http://smsrecei ...

  7. 跟我一起学.NetCore之配置变更监听

    前言 通常程序中配置少不了,配置的修改也避免不了,配置的热更新为此给应用程序带来很大的便捷,不用重启,提高用户体验:但往往有时候需要对修改进行审计,也就是需要记录,有时候也会针对配置修改的时候触发相关 ...

  8. 5.SSH 免密码登陆

    SSH 免密码登陆 serverA 机器上 userA 用户,想要免密钥登陆到serverB机器上 1.集群中的所有机器 安装ssh 服务端sudo apt-get updatesudo apt-ge ...

  9. 数字货币比特币以太坊买卖五档行情数据API接口

    数字货币比特币以太坊买卖五档行情数据API接口       数字货币一般包含比特币BTC.以太坊ETH.瑞波币XRP.泰达币USDT.比特币现金BCH.比特币SV.莱特币LTC.柚子币EOS.OKB. ...

  10. 玩转Spring——Spring AOP

    什么是AOP?AOP(Aspect Oriented Programming )被称为面向切面编程AOP利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共 ...