React机制和diff算法

1、setState机制

理想情况下:

setState是异步的,调用setState只会提交一次state修改到队列中,不会直接修改this.state。等到满足一定条件时,react会合并队列中的所有修改,触发一次update流程,更新this.state

由于setState会触发update过程,因此在update过程中必经的生命周期中调用setState会存在循环调用的风险,另外用于监听state更新完成,可以使用setState方法的第二个参数,回调函数。在这个回调中读取this.state就是已经批量更新后的结果

特殊情况下:

(1)mount流程中调用setState,不会进入update流程,队列在mount时合并修改并render

(2)setTimeout/Promise回调中调用setState,将不会进行队列的批更新,而是直接触发一次update流程


2、diff算法

三条策略:

(1)WebUI中DOM节点跨节点的操作特别少,可以忽略不计

(2)拥有相同类的组件会拥有相似的DOM结构。拥有不同类的组件会生成不同的DOM结构。

(3)同一层级的子节点,可以根据唯一的ID来区分

针对这三个策略,react diff实施的具体策略是:

(1)diff对树进行分层比较,只对比两棵树同级别的节点。跨层级移动节点,将会导致节点删除,重新插入,无法复用

(2)diff对组件进行类比较,类相同的递归diff子节点,不同的直接销毁重建。diff对同一层级的子节点进行处理时,会根据key进行简要的复用。两棵树中存在相同key的节点时,只会移动节点

另外,在对比同一层级的子节点时,diff算法会以新树的第一个子节点作为起点遍历新树,寻找旧树种与之相同的节点。如果节点存在,则移动位置,如果不存在,则新建一个节点。在这个过程中,维护了一个字段lastIndex,这个字段表示已遍历的所有新树子节点在旧树种最大的index。在移动操作时,只有旧的index小于lastIndex的才会移动

3、正确使用diff算法

(1)不适用跨层级移动节点的操作

(2)对于条件渲染多个节点时,尽量采用隐藏等方式切换节点,而不是替换节点

(3)尽量避免将后面的子节点移动到前面的操作,当节点数量较多时,会产生一定的性能问题

4、Fiber是什么?有什么用?

在React15版本的时候,如有组件要更新,则会递归向下遍历整个虚拟DOM树来判断需要更新的地方。这种递归的方式弊端在于无法中断,这要会造成如果我们需要更新一些庞大的组件,那么更新过程就会长时间阻塞主线程,从而造成用户的交互、动画的更新等都不能及时响应。

React组件更新过程简言之就是在持续调用函数的过程,这样的过程会形成一个虚拟的调用栈。加入能控制这个调用栈的执行,把整个更新任务拆解开,尽可能将更新任务放在浏览器空闲时间去执行,那么就能解决以上问题

Fiber重新实现了React的核心算法,他有能力将整个更新任务拆分为一个个小的任务,并且能控制这些任务的执行,主要包括两个核心技术:

(1)新的数据结构fiber

fiber被认为是一个工作单元,执行更新任务的整个流程(不包括渲染)就是在反复寻找工作单元并运行他们,实现拆分任务的功能。拆分成工作单元的目的就是为了能控制stack frame(调用栈中的内容),可以随时随地执行他们,由此使得我们在每运行一个工作单元后都可以按照情况继续执行或中断工作(中断的决定权在于调度器)。fiber内部存储了很多上下文信息,可以把它认为是改进版的虚拟DOM,同样也对应了组件实例及DOM元素。同时fiber也会组成fiber tree,但结构不再是一个树形,而是一个链表的结构

```

{

//浏览器环境下指DOM节点

stateNode: any,

//形成列表结构

return: Fiber | null,

child: Fiber | null,

sibling: Fiber | null,

//更新相关

pendingProps: any, //新的props

memoizedProps: any, //旧的props

//存储setState中的第一个参数

updateQueue: UpdateQueue | null,

memoizedState: any, //旧的state

//调度相关

expirationTime: ExpirationTime, //任务过期时间

//大部分情况下每个fiber都有一个替身fiber

//在更新过程中,所有操作都在替身上完成,当渲染完成后,替身会替代本身

alternate: Fiber | null,

//先简单任务是更新DOM相关的内容

effectTag: SideEffectTag,  //指这个节点需要进行的DOM操作

//以下三个属性也会形成一个链表

nextEffect: Fiber | null,  //下一个需要进行DOM操作的节点

firstEffect: Fiber | null,  //第一个需要进行DOM操作的节点

lastEffect: Fiber | null,  //最后一个需要进行DOM操作的节点,同时也可用于恢复任务

}

```

Fiber和fiber不是同一个概念。前者代表新的调和器,后者代表fiber node,也可以认为是改进后的虚拟DOM

(2)调度器

每次有新的更新任务发生的时候,调度器都会按照策略给这些任务分配一个优先级。通过这个优先级可以获取一个该更新任务必须执行的截止时间,优先级越高截止时间就越近,反之亦然。调度器通过实现requestIdleCallback函数来做到在浏览器空闲的时候去执行这些更新任务。简单的说,就是通过定时器的方式来获取每一帧的结束时间,得到每一帧的结束时间就能判断当下距离结束时间的差值。如果还未到结束时间,则可以继续执行更新任务,如果已经过了结束时间,那么当前帧已经没有时间执行任务,必须把执行权交还给浏览器,即打断任务的执行。另外当开始执行更新任务时,如果有新的更新任务进来,那么调度器就会按照两者的优先级大小来进行决策。如果新的任务优先级小,那么继续当下的任务,如果新的任务优先级大,那么会打断任务并开始新的任务

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

  • 文章首发于个人博客 这是我 Deep In React 系列的第二篇文章,如果还没有读过的强烈建议你先读第一篇:详...
    勿忘巛心安阅读 1,041评论 1 2
  • 前言 Facebook 的研发能力真是惊人, Fiber 架构给 React 带来了新视野的同时,将调度一词介绍给...
    Floveluy阅读 1,752评论 1 5
  • 背景 前段时间准备前端招聘事项,复习前端React相关知识;复习React16新的生命周期:弃用了componen...
    萧强阅读 2,206评论 0 2
  • 跟一起包邮的小伙伴约超市,按着在济南的习惯一溜一溜的逛,逛到乳制品那圈我发现今天的冠益乳不论高的矮的都粘了一个小王...
    远山夕颜阅读 141评论 0 0
  • 欢迎访问我的博客https://qqqww.com,祝码农同胞们早日走上人生巅峰,迎娶白富美~~~ 1 图解Vue...
    这里王工头阅读 621评论 0 0