浅谈 React 与 Vue 更新机制的差异
前言
哈喽,大家好,我是 Baker !🎉
对于前端的 Vue 和 React 相信大家并不陌生,这两个库有着截然不同的设计思想和发展目标,对于我们上层使用者来说,研究它们的差异不仅让我们更加深入的去理解这些库的设计思想,也能帮助我们在开发中更有依据的去选择合适的框架。
本篇文章就两者的更新机制来浅淡一下它们的区别,因为是浅淡并且也受限于篇幅,所以这里并不会就某些技术细节进行展开,如果大家想要深入去了解两者技术的实现,可以尝试去读一下源码,或者期待一波博主后续的更新🌹
因为不涉及技术细节,大家放轻松,悠闲自在的观看即可。
好啦,让我们开始吧!
Vue 更新机制
Vue 使用著名的响应式系统来收集依赖和派发更新,当模板中数据发生变化时,组件的 render 函数会被作为数据的依赖而被触发,只不过这个触发并不是立刻的,因为模板中会引用很多数据,render 同时是这些所有数据的依赖项,如果 render 每次都立刻执行,则会造成多次重复渲染而消耗性能。
实际上 render 是被 update 调用的,而 update 又是 Watcher 调用的,而 Watcher 在收到 Dep 的派发更新时会把自身交给 Scheduler ,由 Scheduler 负责对其去重并通过 nextTick()
将这些 Watcher 包装成微任务放入到事件循环中等待调用。
render 执行输出的结果是一颗新的虚拟 DOM 树,然后 update 会通过 patch 函数将它与旧的虚拟 DOM 树进行对比,diff 和真实 DOM 的操作过程既是在 patch 函数中进行。
所以,其实 Vue 的整个更新任务(构建虚拟 DOM ,diff,操作真实 DOM)可以算作一个整体,这个整体被当作微任务来处理,这也就是 Vue 异步更新的原理。
最后附上一张 Vue 官方文档的流程图:
React 更新机制
这里以 React16 之后的 Fiber 架构为例。
React 没有 Vue 的响应式系统,它的更新主要是靠用户手动的调用副作用函数(比如 setState 等)来触发( Vue 则是系统自动触发)。所有的更新任务(如调用 setState )会被 render 阶段的 Scheduer 进行调度,它会将多次的 setState 调用合并为一次更新操作,render 阶段可以随时被打断(如遇到高优先级任务、当前事件循环没有足够的时间了、发生了其它错误等)。
Scheduer 调度器负责对任务进行调度,内部会通过任务的优先级(会通过一系列的优先级设置任务的 delay ),以及当前事件循环空闲的时间等来判断当前任务是否可以执行,如果可以执行则会通过 MessageChannel 将任务包装成一个宏任务推入到事件循环当中等待执行,在任务执行时通过 render 阶段的 Reconciler 来进行协调。
Scheduer 判断当前任务是否可以执行的调度可以通过原生的 requestIdleCallback 来进行简单模拟,因为这个 Api 就是在浏览器空闲时期被调用。
Reconciler 通过递和归两个阶段来创建新的 Fiber Tree 和进行副作用的收集(这个副作用指的是 DOM 的更新操作)( diff 发生在此),至此 render 阶段结束,之后就来到了 commit 阶段,该阶段只有一个 Readerer 执行,并且是同步执行,Readerer 主要就是根据 Fiber Tree 标记的副作用来进行真实 DOM 的创建、更新和删除操作。
区别
其实大体上 Vue 和 React 的更新机制都是构建虚拟DOM、diff、操作真实DOM这三个主要过程,它们的主要区别主要体现在触发更新的机制和一些细节上:
-
触发更新机制:Vue 是通过响应式系统自动及时的进行触发,而 React 则是通过用户更改状态的操作然后进行一系列调度来触发更新。
-
任务的区别:Vue 会将任务包装成微任务,而 React 则是将其包装成宏任务。
虽然都是异步任务,但它们有很大区别。在事件循环中,如果有微任务存在则会先一直执行微任务,直到把微任务队列清空,然后再执行宏任务,并且在每个宏任务执行完毕后,会立即检查并执行所有微任务,然后再进行下一个宏任务的执行。
先明确一点:异步任务执行时是由主线程进行执行的,所以此时它们已经相当于是同步执行了(这个异步实际指的是异步任务在任务队列里面等待的时候不会影响主线程的执行)
微任务执行时不会穿插其它任务(比如浏览器渲染),所以当有大量微任务堆积时可能就会阻塞浏览器渲染(异步任务),但执行完一个宏任务时如果遇到浏览器需要渲染,则不会继续执行下一个宏任务而是转去进行浏览器渲染然后开启新的一轮事件循环。
- 因为 React 的 Fiber 架构的出现就是为了能够随时打断,把控制权交给主线程,所以 React 采用的是宏任务,而不是会一股脑 “ 全冲完 ” 的微任务,这样可以避免微任务过多而导致的任务堆积和性能问题。
- 也正是因为 Vue 的理念是追求响应性和即时效果并避免过多的渲染,所以它采用微任务,及时把更新任务处理完,最后让浏览器渲染一次即可。
- 其实现如今,React 和 Vue 都不是完全使用某一种任务,在一些情况下 React 也会使用微任务,Vue 亦是如此,它们的目标都是想要结合自身情况来创造一个更优秀的框架。
-
diff 算法的不同:Vue 采用双端对比,而 React 使用的是 Reconciliation 算法。
Reconciliation 算法是React 整体的更新策略,并不只是简单的 diff 算法。简单来说 React 的 diff 过程会对单节点和多节点分别计算(都是遍历 Fiber 链表进行的),多节点的情况会分两轮遍历,第一轮遍历会尝试逐个的复用节点,第二轮遍历处理上一轮遍历中没有处理完的节点。
React 不使用双端 diff 的原因:
React 源码中的原话:This algorithm can’t optimize by searching from boths ends since we don’t have backpointers on fibers. I’m trying to see how far we can get with that model. If it ends up not being worth the tradeoffs, we can add it later.(这种算法不能通过从两端搜索来优化,因为我们在 Fiber 对象上没有反向指针。我正试着看看我们能用这个模型走多远,如果这种方式不理想,以后再考虑实现两端搜索。)
并且源码中还提到,React 认为对于列表反转和需要进行双端搜索的场景是少见的,所以综合以上情况, React 暂时还不会使用双端 diff。
结语
还是那句话,本篇文章只是浅淡,Vue 和 React 的更新机制非常复杂,其中涉及的知识点很多,比如 Vue 的响应式原理、Vue 双端 diff 流程、React Fiber 架构、Fiber 双缓冲、React Reconciler 递和归两阶段流程等等。
本文简单梳理了一下它们更新机制的整体流程,希望能基于此来为大家展开一个清晰的脉络,如果在阅读过程中发现了问题,欢迎评论区留言交流!
如果本篇文章对你起到了帮助,还请大家不要吝啬手中的点赞、评论、收藏和关注,我们下次再见!
最近忙着秋招,更新频率虽然降低了,但是我写文章的热情可是一点没减,期待下次好文相见!
相关文章:

浅谈 React 与 Vue 更新机制的差异
前言 哈喽,大家好,我是 Baker !🎉 对于前端的 Vue 和 React 相信大家并不陌生,这两个库有着截然不同的设计思想和发展目标,对于我们上层使用者来说,研究它们的差异不仅让我们更加深入的去理解…...

Delft3D水动力与泥沙运动模拟实践技术应用
水体中泥沙运动是关系到防洪,调水等方面的重要问题,也是水利和水环境领域科研热点之一。水利数值模型,在环境影响评价、防洪规划等方面也有着广泛的应用。荷兰Delft研究所开发的Delft3D模型是世界上最先进的水动力之一,能够运用于…...

Linux 本地Yearning SQL 审核平台远程访问
文章目录 前言1. Linux 部署Yearning2. 本地访问Yearning3. Linux 安装cpolar4. 配置Yearning公网访问地址5. 公网远程访问Yearning管理界面6. 固定Yearning公网地址 前言 Yearning 简单, 高效的MYSQL 审计平台 一款MYSQL SQL语句/查询审计工具,为DBA与开发人员使用…...

Redis集群(Cluster)
1. 什么是集群 广义的集群:只要是多台机器,构成一个分布式系统,就可以称为一个“集群”。像前面的主从结构,哨兵模式都是“广义的集群”狭义的集群:redis提供的集群模式,这个集群模式主要解决存储空间不足…...

Scapy 解析 pcap 文件从HTTP流量中提取图片
Scapy 解析 pcap 文件从HTTP流量中提取图片 前言一、网络环境示例二、嗅探流量示例三、pcap 文件处理最后参考 作者:高玉涵 时间:2023.9.17 10:25 环境:Linux kali 5.15.0-kali3-amd64,Python 3.11.4,scapy…...

难得有个冷静的程序员发言了:纯编码开发实施的项目,失败的案例也有很多
难得有个冷静的程序员发言了:纯编码开发实施的项目,失败的案例也有很多。假如用低代码实施,能达到不失败或提高成功率,对软件开发项目交付,会是重大的价值。 我的观点:两者都可能失败,不同的是&…...
Leetcode.146 LRU 缓存
题目链接 Leetcode.146 LRU 缓存 mid 题目描述 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 c a p a c i t y capacity capacity 初始化 LRU 缓存int get(int key) 如果关键…...

科技资讯|Canalys发布全球可穿戴腕带设备报告,智能可穿戴增长将持续
市场调查机构 Canalys 近日发布报告,表示 2023 年第 2 季度全球可穿戴腕带设备出货量达 4400 万台,同比增长了 6%。 主要归功于其亲民的价格以及消费者对价位较高的替代品仍持谨慎态度,基础手环市场尽管与去年同期相比有所下降,…...
使用https接口,无法调通接口响应不安全
网页pc使用不安全https 页面提示不安全–点击高级–跳过 接口使用部安全https 无法像页面一样可以跳过 方法:安装证书 还是无法响应报错不安全: 1、确定证书绑定ip还是域名(ip和域名都可以绑定) 使用的是httpsip,报…...

uniapp开发h5,解决项目启动时,Network: unavailable问题
网上搜了很多,发现都说是要禁用掉电脑多余的网卡,这方法我试了没有好,不晓得为啥子,之后在网上看,uniapp的devServer vue2的话对标的就是webpack4的devserver(除了复杂的函数配置项),…...
9.17 校招 实习 内推 面经
绿泡*泡: neituijunsir 交流裙 ,内推/实习/校招汇总表格 1、自动驾驶一周资讯 - 一汽与Mobileye 签署战略合作,小鹏汽车将用经销商销售逐渐替换直营模式,原小鹏汽车副总裁加盟赛力斯 自动驾驶一周资讯 - 一汽与Mobileye 签署战…...

【Python小项目之Tkinter应用】随机点名/抽奖工具大优化:新增查看历史记录窗口!语音播报功能!修复预览文件按钮等之前版本的bug!
文章目录 前言一、实现思路二、关键代码查看历史记录按钮语音播报按钮三、完整代码总结前言 老生常谈,先看效果:(订阅专栏可获取完整代码) 初始状态下,我们为除了【设置】外的按钮添加弹窗,提示用户在使用工具之前要先【设置】。在设置界面,我们主要修改了【预览文件】…...

数据结构与算法:排序算法(1)
目录 冒泡排序 思想 代码实现 优化 鸡尾酒排序 优缺点 适用场景 快速排序 介绍 流程 基准元素选择 元素交换 1.双边循环法 使用流程 代码实现 2.单边循环法 使用流程 代码实现 3.非递归实现 排序在生活中无处不在,看似简单,背后却隐藏…...

NotePad++ 在行前/行后添加特殊字符内容方法
我们在处理数据时,会遇到需要在每行数据前面、后面、开头、结尾添加各种不一样的字符 如果数据不多,我们可以自己手动的去添加,但如果达到了成百上千行,此时再机械的手动添加是不现实的 这里教给大家如何快速的在数据每行的前后…...

【JavaEE】多线程案例-线程池
文章目录 1. 什么是线程池2. 为什么要使用线程池(线程池有什么优点)3. 如何使用Java标准库提供的线程池3.1 创建一个线程池对象3.2 什么是工厂模式3.3 为什么要使用工厂模式3.4 Executors 创建不同具有不同特性的线程池3.5 ThreadPool 类的构造方法3.6 线…...

服务器搭建(TCP套接字)-fork版(服务端)
基础版的服务端虽然基本实现了服务器的基本功能,但是如果客户端的并发量比较大的话,服务端的压力和性能就会大打折扣,为了提升服务端的并发性能,可以通过fork子进程的方式,为每一个连接成功的客户端fork一个子进程,这样…...
缺失的第一个正数:高效解法与技术
缺失的第一个正数:高效解法与技术 背景 在计算机编程中,有时候需要寻找一个未排序整数数组中没有出现的最小的正整数。这篇技术博客将详细讨论这个问题,并提供一个时间复杂度为 O(n) 且只使用常数级别额外空间的解决方案。 问题描述 leet…...
常用的辅助网站(持续更新)
标题 一、uni-app方向二、H5方向 一、uni-app方向 1、uni-app官网 地址:https://uniapp.dcloud.net.cn/ 2、香蕉云编 地址:https://www.yunedit.com/ 描述:一般用来配置ios证书或安卓证书、上传ios包至商店 3、uView 地址:http…...

LeetCode 75 - 01 : 最小面积矩形
type pair struct{x, y int }func minAreaRect(points [][]int)int{mp : map[pair]struct{}{}// 将二维数组中的坐标映射到map中for i : range points{mp[pair{points[i][0], points[i][1]}] struct{}{}}// 将结果设置为一个最大值,防止影响求最小值的逻辑res : ma…...

每日一题:请解释什么是闭包(Closure)?并举一个实际的例子来说明。(前端初级)
今天继续在前端初级笔试题中被AI虐: 碱面的答案,问题:初级,回答:初级https://bs.rongapi.cn/1702510598371151872/14我的回答如下: 闭包是指由大括号包裹的一个区域,这个区域代表了一个变量生效…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...

MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...

tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...

Sklearn 机器学习 缺失值处理 获取填充失值的统计值
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...

软件工程 期末复习
瀑布模型:计划 螺旋模型:风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合:模块内部功能紧密 模块之间依赖程度小 高内聚:指的是一个模块内部的功能应该紧密相关。换句话说,一个模块应当只实现单一的功能…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...

C++_哈希表
本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说,直接开始吧! 一、基础概念 1. 哈希核心思想: 哈希函数的作用:通过此函数建立一个Key与存储位置之间的映射关系。理想目标:实现…...