探索 JavaScript 事件机制(四):React 合成事件系统
前言
在前端开发中,事件处理是不可或缺的一部分。在众多的前端框架中,React 凭借其高效和灵活性受到众多开发者的喜爱。React 的事件处理系统,即“合成事件系统”,是其性能优化的一大亮点。
本文将带你深入浅出地探索 React 的合成事件系统,了解其原理和优势。
合成事件系统简介
React 的合成事件系统(Synthetic Event System)是对浏览器原生事件的封装和优化。它不仅统一了不同浏览器的事件模型,还提供了更高效的事件处理机制。通过合成事件,React 可以实现更好的性能和跨浏览器兼容性。
为什么需要合成事件?
- 跨浏览器兼容性:不同浏览器的事件模型存在差异,React 的合成事件系统可以屏蔽这些差异,提供一致的事件处理接口。
- 性能优化:React 使用事件委托机制,将所有事件处理器绑定到根节点上,从而减少内存占用和频繁的 DOM 操作。
- 统一接口:通过合成事件,React 提供了一套统一的事件对象,开发者可以更方便地处理各种事件。
事件委托机制
在传统的事件处理方式中,我们通常会为每个需要处理事件的元素单独绑定事件处理器。而在 React 中,合成事件系统采用了事件委托机制,将所有的事件处理器统一绑定到应用的根节点上。当事件触发时,事件会冒泡到根节点,再由根节点上的事件处理器统一处理。
事件委托的优势
- 降低内存消耗:只需要在根节点上维护一个事件处理器,避免为每个元素单独分配内存。
- 减少 DOM 操作:通过统一的事件处理机制,可以减少频繁的 DOM 操作,提高性能。
- 方便管理:所有事件处理器都集中在根节点上,方便统一管理和调试。
React 合成事件的内部实现
事件池机制
React 为了优化事件处理的性能,引入了事件池(Event Pool)机制。事件池是一个用来复用合成事件对象的池子,避免频繁创建和销毁事件对象,从而减少内存开销和垃圾回收。
在事件触发时,React 从事件池中取出一个合成事件对象,对其进行初始化,并在事件处理完成后,将其重置并放回事件池中。
创建合成事件
React 合成事件是对原生事件的封装,对象包括各种事件类型,例如 SyntheticMouseEvent、SyntheticKeyboardEvent 等。这些合成事件对象统一派生自 SyntheticEvent 基类。
class SyntheticEvent {constructor(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) {this.dispatchConfig = dispatchConfig;this._targetInst = targetInst;this.nativeEvent = nativeEvent;// 根据原生事件对象初始化合成事件对象的属性for (let propName in nativeEvent) {if (!nativeEvent.hasOwnProperty(propName)) continue;this[propName] = nativeEvent[propName];}// 其他初始化逻辑...}preventDefault() {this.defaultPrevented = true;const event = this.nativeEvent;if (event.preventDefault) {event.preventDefault();} else {event.returnValue = false;}}stopPropagation() {const event = this.nativeEvent;if (event.stopPropagation) {event.stopPropagation();} else {event.cancelBubble = true;}}// 重置合成事件对象destructor() {for (let propName in this) {if (this.hasOwnProperty(propName)) {this[propName] = null;}}}
}
事件调度与分发
React 使用事件调度器(Event Dispatcher)来管理和分发事件。当事件触发时,React 会捕获到该事件,并通过事件调度器查找对应的事件处理函数,进行调用。
事件调度分为三个阶段:
- 捕获阶段(Capture Phase):从根节点到目标元素逐步捕获事件。
- 目标阶段(Target Phase):在目标元素上触发事件处理函数。
- 冒泡阶段(Bubble Phase):从目标元素逐步冒泡回根节点,触发冒泡事件处理函数。
function dispatchEvent(event, topLevelType, targetInst) {const nativeEvent = event.nativeEvent;// 构建合成事件对象const syntheticEvent = new SyntheticEvent(topLevelType,targetInst,nativeEvent,nativeEvent.target);// 捕获阶段调度事件traverseTwoPhase(targetInst, accumulateDirectionalDispatches, syntheticEvent);// 目标阶段调度事件accumulateDispatches(targetInst, syntheticEvent);// 冒泡阶段调度事件traverseTwoPhase(targetInst, accumulateDirectionalDispatches, syntheticEvent, true);// 处理事件队列runEventQueueInBatch(syntheticEvent);
}
React 合成事件处理流程
事件处理器的绑定
在 React 中,我们通过 onEventName 属性绑定事件处理器。例如:
<button onClick={this.handleClick}>Click Me</button>
编译后的代码中,React 会将 handleClick 函数绑定到事件调度器中,并在事件触发时调用。
事件处理器的执行
当事件触发时,React 会根据事件类型和目标元素,从事件调度器中找到对应的事件处理函数,并依次调用。这其中涉及事件捕获和冒泡机制。
事件的清理
在事件处理完成后,React 会重置合成事件对象并将其放回事件池中,等待下次复用。这一过程减少了垃圾回收的频率,提高了性能。
总结
React 合成事件系统通过事件池机制、事件调度与分发机制,实现了高效的事件处理和跨浏览器兼容性。理解其内部实现原理,有助于我们更好地优化和调试 React 应用。
相关文章:
探索 JavaScript 事件机制(四):React 合成事件系统
前言 在前端开发中,事件处理是不可或缺的一部分。在众多的前端框架中,React 凭借其高效和灵活性受到众多开发者的喜爱。React 的事件处理系统,即“合成事件系统”,是其性能优化的一大亮点。 本文将带你深入浅出地探索 React 的合…...

openlayers 封装加载本地geojson数据 - vue3
Geojson数据是矢量数据,主要是点、线、面数据集合 Geojson数据获取:DataV.GeoAtlas地理小工具系列 实现代码如下: import {ref,toRaw} from vue; import { Vector as VectorLayer } from ol/layer.js; import { Vector as VectorSource } fr…...
手机号码携号转网查询接口-在线手机号码携号转网查询-手机号码携号转网查询API
接口简介:通过手机号精准查询该号码转网前及转网后所归属运营商 可查询号码是否为虚拟手机号 可查询到号码归属地信息 高准确率,实时查询运营商数据库 多用于营销场景,如运营商业务办理、客户信息查询、携号转网、电话营销等 接口地址&#x…...

yolo目标检测和姿态识别和目标追踪
要检测摄像头画面中有多少人,人一排排坐着,像教室那样。由于摄像头高度和角度的原因,有的人会被遮挡。 yolo v5 首先需要下载yolo v5官方代码,可以克隆或下载主分支的代码,或者下载release中发布的。 简单说一下环境…...
Docker搭建开源Web云桌面操作系统Puter和DaedalOS
文章目录 Puter 操作系统说明基于 Docker 启动 Puter 操作系统拉取镜像运行容器基于 Docker-Compose 启动 Puter操作系统创建目录编写docker-compose.yml运行在本地直接运行puter操作系统puter界面截图puter个人使用总结构建自己的Puter镜像daedalos基于web的操作系统说明技术特…...
FAQ-为什么交换机发给服务器的日志显示的时间少8小时
问题描述 配置交换机向日志服务器发送日志,在交换机上面查看日志显示的时间比日志服务器显示的时间快8个小时 解决方案 根据公司全球化整改的要求,syslog默认发送的是UTC时间。 当前设备上配置了时区UTC8,因此,设备上显示的本地…...

[表达式]真假计算
题目描述 有一棵树,不一定是二叉树。 所有叶子节点都是 True 或者 False。 对于从上往下奇数层的非叶子节点是 and,偶数层非叶子节点为 or。 树上每个节点的值是所有孩子节点的值进行该节点的运算操作。 判断一棵树能否砍掉,最快的方法就是从…...

记录一次线上环境svchost.exe antimalware service executable 进程占用CPU过高问题
博主介绍: 大家好,我是想成为Super的Yuperman,互联网宇宙厂经验,17年医疗健康行业的码拉松奔跑者,曾担任技术专家、架构师、研发总监负责和主导多个应用架构。 技术范围: 目前专注java体系,有多…...

Docker 部署 EMQX 一分钟极速部署
部署 EMQX ( Docker ) [Step 1] : 拉取 EMQX 镜像 docker pull emqx/emqx:latest[Step 2] : 创建目录 ➡️ 创建容器 ➡️ 拷贝文件 ➡️ 授权文件 ➡️ 删除容器 # 创建目录 mkdir -p /data/emqx/{etc,data,log}# 创建容器 docker run -d --name emqx -p 1883:1883 -p 1808…...

STL-常用容器-list
1list基本概念 **功能:**将数据进行链式存储 链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的 链表的组成:链表由一系列结点组成 结点的组成:一个是存储…...
Lambda 架构
Lambda架构是一种用于构建可扩展、容错和实时数据处理系统的架构模式。 它由三个主要部分组成:批处理层(Batch Layer)、实时层(Speed Layer)和服务层(Serving Layer)。 Lambda架构旨在结合批处…...

Windows电脑设置网络唤醒(Wake-on-LAN)
1. 启用 Windows 电脑的 Wake-on-LAN 功能 首先,你需要确保你的 Windows 电脑支持并启用了 Wake-on-LAN: BIOS/UEFI 设置(具体看自己电脑主板如何设置): 启动 Windows 电脑,进入 BIOS/UEFI 设置。找到网络适配器相关的设置,启用 …...
前端项目构建流程
1. 需求分析 目标:明确项目目标、核心功能和用户需求。 产品需求讨论: 与产品经理、客户、业务部门讨论项目的需求和目标,理解产品的功能、业务流程以及用户需求。定义用户角色(Persona),明确不同用户的功…...

支持国密算法的数字证书-国密SSL证书详解
在互联网中,数字证书作为标志通讯各方身份信息的数字认证而存在,常见的数字证书大都采用国际算法,比如RSA算法、ECC算法、SHA2算法等。随着我国加强网络安全技术自主可控的大趋势,也出现了支持国密算法的数字证书-国密SSL证书。那…...

【EndNote使用教程】创建文献库、导入文献、文献分类
1、创建文献库 打开“EndNote”,点击“文件”,点击“新建”,选择保存文件路径。 2、导入文献 (1)可以选择导入电脑上的PDF文件,如下图所示。 (2) 也可以选择直接在浏览器网页上面直…...

双十一电容笔选哪个好?!西圣、益博思、吉玛仕电容笔实测对比!
当数码测评博主几年年,我也实测过不下10款电容笔了,对电容笔这个品类也算是半个内行人了。提到电容笔,在平替品牌的追逐中,西圣、益博思、吉玛仕这三款作为国货黑马一直备受瞩目,综合各大电商平台的销量榜、好评口碑榜…...
房地产网络安全:主要风险及缓解建议
房地产行业已开始数字化转型,因此极易受到网络犯罪的攻击。潜在风险的清单很长:从客户敏感信息的数据泄露到勒索软件攻击,网络犯罪分子将房地产公司视为其所携带的所有类型敏感信息的高价值目标。 在本文中,我们将探讨房地产领域…...

玩转大模型的第一步——提示词(Prompt)工程【抛砖篇】
前言 AI大模型提示词工程,又名 LLM prompts Project,指的是在使用大型语言模型(如OpenAI的GPT系列)时,用于引导模型生成特定响应的输入,是在使用AI大模型过程中非常重要的一个环节,是模型生成文…...

火山引擎数据飞轮线上研讨会即将开启,助力消费品牌双十一造爆款
随着双十一的临近,各大品牌方的备战工作已进入紧张而有序的倒计时阶段。这场持续十多年的电商大促,对消费者来说是购物狂欢节,对各大品牌方来说,则是更是品牌实力与策略的比拼。面对日益激烈的市场竞争,如何更好地撬动…...

【python实战】利用代理ip爬取Alibaba海外版数据
引言 在跨境电商的业务场景中,数据采集是分析市场、了解竞争对手以及优化经营策略的重要环节。然而,随着越来越多企业依赖数据驱动决策,许多跨境电商平台为了保护自身数据,采取了更严格的防护措施。这些平台通过屏蔽大陆IP地址或部…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...