最近撸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. pandas | 详解DataFrame中的apply与applymap方法

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是pandas数据处理专题的第5篇文章,我们来聊聊pandas的一些高级运算. 在上一篇文章当中,我们介绍了panads的一些计算方法, ...

  2. 2020-05-08:mycat部署数据库集群的时候 遇到了哪些坑

    福哥答案2020-05-08:答案仅供参考,来自群员 使用activity时,连接mycat设置进去的序列化的流程变量,反序列化会报错这个类型字段类型是blob类型,mycat对这种类型处理时有点问题

  3. elementUI 表单清空问题

    在使用表单的清空方法时,我们需要注意几个问题: 1.我们需要为每个form-item加上prop属性,要不然无法清空(大部分的问题就是出在这) 2.resetFields()方法是重置表单,重置为默认 ...

  4. 使用halo搭建自己的博客并配置https域名访问

    首先进行java配置 # 1. 下载jdk [下载地址](https://www.oracle.com/cn/java/technologies/javase-downloads.html) - 一定 ...

  5. windows安装cnpm步骤

    1.首先前往nodejs官网下载nodejs 2.安装nodejs 3.打开cmd,输入npm -v,检查npm是否安装成功.成功返回的话返回输出版本号 4.安装cnpm,输入npm install ...

  6. Git常用命令参考手册

    配置 # 查看全局配置列表 git config -l # 查看局部配置列表 git config --local --list # 查看已设置的全局用户名/邮箱 git config --globa ...

  7. Java字符串中有多少个字符多少个char、字节

    Java 中Char是两个字节,Char在Java中也被称为代码单元(Code Unit) . Java中的字符与代码点(Code Unit)一 一对应,而可能对应一个或者两个 代码单元 字符串的le ...

  8. TestLink使用指南

    TestLink安装上之后,局域网内用户可以登陆使用,下面介绍本软件的使用方式. 1.TestLink简介 TestLink是基于Web的开源测试管理工具,用户可以使用这个工具创建测试项目和测试用例, ...

  9. 精讲RestTemplate第8篇-请求失败自动重试机制

    本文是精讲RestTemplate第8篇,前篇的blog访问地址如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 精讲RestTemplate第2篇-多种底层H ...

  10. Jmeter系列(49)- 详解 HTTP Cookie 管理器

    如果你想从头学习Jmeter,可以看看这个系列的文章哦 https://www.cnblogs.com/poloyy/category/1746599.html 简单介绍 功能一 首先,它像网络浏览器 ...