最近撸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. Python多进程实现并行化随机森林

    文章目录 1. 前言 2. 随机森林原理 3.实现原理 3.1并行化训练 3.1.1训练函数 3.1.2 单进程训练函数 生成数据集模块--生成部分数据集 单进程训练函数代码 3.2 并行化预测 3. ...

  2. 洛谷P1308.统计单词数(字符串匹配)

    题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数. 现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给 ...

  3. 汇编 | x86汇编指令集大全(带注释)

    做mit-6.828的时候遇到了很多汇编知识,但是无奈学校还没学汇编,只能狠心啃啃硬骨头,在网上查到了很多的资料,归档!方便查看 ----------------------------------- ...

  4. Cannot instantiate the type ......的解决

    使用public abstract class MainWindow implements ActionListener{} 之后创建对象MainWindow window = new MainWin ...

  5. nova start 虚机的代码流程分析

    nova start 虚机的代码流程分析,以ocata版本为分析基础1.nova api服务接受用户下发的 nova start启动虚机请求其对应的http restfull api接口为post / ...

  6. 如何为指定python解释器安装pip

    有时候我们通常会有很多python解释器,例如python2.python3.python(Anaconda). 参考链接:https://www.cnblogs.com/michaelcjl/p/1 ...

  7. NeuroAttack: Undermining Spiking Neural Networks Security through Externally Triggered Bit-Flips

    郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! arXiv:2005.08041v1 [cs.CR] 16 May 2020 Abstract 由于机器学习系统被证明是有效的,因此它被广 ...

  8. 如何寻找决策最优解?熵权TOPSIS助你科学决策

    熵权topsis是一种融合了熵值法与TOPSIS法的综合评价方法.熵值法是一种客观赋值法,可以减少主观赋值带来的偏差:而topsis法是一种常见的多目标决策分析方法,适用于多方案.多对象的对比研究,从 ...

  9. muduo源码解析5-mutex相关类

    mutexlock和mutexlockguard class mutexlock:noncopyable { }: class mutexlockguard:noncopyable { }: 作用: ...

  10. java父类子类代码

    import java.util.Scanner;import java.util.*; class PersonF{ public void print(String ID,String Workc ...