React16源码: ConcurrentMode的使用及源码实现

news/2024/7/15 3:11:32 标签: react.js, 前端

ConcurrentMode

1 ) 概述

  • ConcurrentMode 是 React 16 出来的一个最令人振奋的功能
  • 在2018年年初是 Async Mode,在发布了16.6之后,名字进行了更新
  • 然后改成了 ConcurrentMode,中间的API有一个过渡的版本,后续会提到
  • 它其实是 React 16 之前已有的概念了
  • 其目标是让 React 的整体渲染过程能够进行一个优先级的排比
  • 并且让整体的一个渲染的过程是能够中断的
  • 它就可以进行一个任务的调度,提升 cpu 性能
    • 因为 js 是一个单线程的语言, 如果我们执行更新占用了非常长的时间
    • 比如,浏览器执行一些动画的渲染中间,被进程占用执行其他操作, 时间被拉长,动画就变得比较卡顿
    • 或者是我们在进行一些input的输入的时候,响应会比较的卡,因为这个时候 js 正在运行react的更新
  • 在这种时候,React 让我们能够去区分一些优先级比较高和比较低的任务
  • 在进行一个 React更新的过程当中,它优先执行优先级高的任务
  • 在等浏览器把这些优先级高的任务,执行完之后,它有空余的时间的时候,再来执行优先级较低的任务

2 ) 实例演示

// ConcurrentMode 以前叫做 unstable_ConcurrentMode // 这个就是上面说的 过渡 API
import React, { unstable_ConcurrentMode as ConcurrentMode } from 'react'; // react 16.6 版本
// import React, { ConcurrentMode } from 'react'; // react 16.7 版本
// 这个会强制执行某个更新操作时, 使用优先级最高方式进行更新
import { flushSync } from 'react-dom;
import './index.css'

class Parent extends React.Component {
  state = {
    async: true,
    num: 1,
    length: 2000,
  }

  componentDidMount() {
    this.interval = setInterval(() => {
      this.updateNum()
    }, 200)
  }

  componentWillUnmount() {
    // 别忘了清除interval
    if (this.interval) {
      clearInterval(this.interval)
    }
  }

  updateNum() {
    const newNum = this.state.num === 3 ? 0 : this.state.num + 1
    if (this.state.async) {
      this.setState({
        num: newNum,
      })
    } else {
      flushSync(() => {
        this.setState({
          num: newNum,
        })
      })
    }
  }

  render() {
    const children = []

    const { length, num, async } = this.state

    for (let i = 0; i < length; i++) {
      children.push(
        <div className="item" key={i}>
          {num}
        </div>,
      )
    }

    return (
      <div className="main">
        async:{' '}
        <input
          type="checkbox"
          checked={async}
          onChange={() => flushSync(() => this.setState({ async: !async }))}
        />
        <div className="wrapper">{children}</div>
      </div>
    )
  }
}

export default () => (
  <ConcurrentMode>
    <Parent />
  </ConcurrentMode>
)
  • 上面 unstable_ConcurrentModeConcurrentMode 的过渡版本
    • 在后续16.7 实验版本的源码中是这样判断的
       var enableStableConcurrentModeAPIS = true // 注意这里是 true
       // ... 中间省略很多代码
       if (enableStableConcurrentModeAPIS) {
          React.ConcurrentMode  = REACT_CONCURRENT_MODE_TYPE;
          React.Profiler = REACT_POFILER_TYPE;
       } else {
          React.unstable_ConcurrentMode  = REACT_CONCURRENT_MODE_TYPE;
          React.unstable_Profiler = REACT_POFILER_TYPE;
       }
      
  • 关于上面的 flashSync 这个API
    • 它会强制我们在执行某一个更新操作的时候,使用优先级最高的方式去进行一个更新
    • ConcurrentMode 有一个特性
      • 我们在一个子树当中渲染了 ConcurrentMode 之后
      • 它下面的所有的节点产生的更新,就是一个低优先级的更新
      • 上面的示例,把整体渲染都放在这个 ConcurrentMode 下面, 所以这个组件它产生的所有更新
      • 就是我们通过 setState 这种方式去创建的这种更新, 它都是处于一个低优先级的
  • 上面的示例,展示了低优先级和高优先级它的一个区别
    • 使用 flashSync 来提高整体的一个优先级
  • 上面示例程序渲染了有2千个节点
    • 每个节点里面的数字是一直在变的,在这个过程当中
    • 我们又给浏览器增加了一个持续性的动画,就是让整体的一个区域左右的移动
    • 动画的优先级明显是较高的
  • 主要关注 updateNum 这个函数的 if else 判断
  • 就是我们通过一个 checkbox 来切换 async 的情况
    • 当结果为 false 时,调用 flashSync,因为它是一个优先级较高的任务,强制立马更新掉
    • 效果就是: 数字变化特别快,但是动画运动就特别卡
  • 这就是 异步模式 (async mode) 和 同步模式(sync mode) 的一个本质的区别
    • 在 async mode 下面会区分优先级,让整体的动画能够看起来更流畅一点
    • 在 sync mode 下面,它没有一个优先级的区别,所以它们都是一起进行的
      • 在进行更新的时候,导致我们整个动画也会变得一卡一卡的感觉

3 )源码探究

在 React.js 中, 看一下 ConcurrentMode 的源码是什么

import {
  REACT_CONCURRENT_MODE_TYPE,
  REACT_FRAGMENT_TYPE,
  REACT_PROFILER_TYPE,
  REACT_STRICT_MODE_TYPE,
  REACT_SUSPENSE_TYPE,
} from 'shared/ReactSymbols';
// ... 省略其他
// 最后
if (enableStableConcurrentModeAPIs) {
  React.ConcurrentMode = REACT_CONCURRENT_MODE_TYPE;
  React.Profiler = REACT_PROFILER_TYPE;
} else {
  React.unstable_ConcurrentMode = REACT_CONCURRENT_MODE_TYPE;
  React.unstable_Profiler = REACT_PROFILER_TYPE;
}
  • 在这里面 ConcurrentMode 它等于的是一个常量,它是一个 REACT_CONCURRENT_MODE_TYPE
  • 是从 shared/ReactSymbols 文件中导入的一个类型,本质是一个 Symbol
    export const REACT_CONCURRENT_MODE_TYPE = hasSymbol
      ? Symbol.for('react.concurrent_mode')
      : 0xeacf;
    
  • 我们自己写组件的时候,我们都知道里面会有特别多的一些东西,我们要写一些 state
    • 比如,业务逻辑 或者在 function component 里面至少渲染一些东西
    • 但是我们这个组件它就是一个简单的 Symbol,没有任何其他的东西
  • 目前,先不去探究它如何来承载其他组件的

http://www.niftyadmin.cn/n/5299166.html

相关文章

Gen-AI 的知识图和分析(无需图数据库)

如今&#xff0c;图表比以往任何时候都更加相关和有用。由于目前正在发生的人工智能革命&#xff0c;工程师们正在考虑围绕 Gen-AI 的机会&#xff0c;利用具有动态提示、数据基础和屏蔽功能的开放 Gen-AI 解决方案&#xff0c;这进一步促使他们思考知识图谱等有效的解决方案。…

leetcode链表小练(1.反转链表2.链表的中间节点3.合并两个有序链表4.环形链表①5.环形链表②)详解 (୨୧• ᴗ •͈)◞︎ᶫᵒᵛᵉ ♡

目录 一.反转链表 思路一反转指针反向&#xff1a; 思路二头插法&#xff1a; 二.链表的中间节点&#xff1a; 三.合并两个有序数组: 思路一&#xff1a;从头开始&#xff0c;取两个链表中小的那个尾插到新链表。定义指针head,tail指向空&#xff0c;代表新链表的头结点。…

脆弱的SSL加密算法漏洞原理以及修复方法

漏洞名称&#xff1a;弱加密算法、脆弱的加密算法、脆弱的SSL加密算法、openssl的FREAK Attack漏洞 漏洞描述&#xff1a;脆弱的SSL加密算法&#xff0c;是一种常见的漏洞&#xff0c;且至今仍有大量软件支持低强度的加密协议&#xff0c;包括部分版本的openssl。其实&#xf…

论文解读:Coordinate Attention for Efficient Mobile Network Design(CVPR2021)

论文前言 原理其实很简单&#xff0c;但是论文作者说得很抽象&#xff0c;时间紧的建议直接看3.1中原理简述CBMA、原理简述CBMA以及3.2中原理简述coordinate attention block即可。 Abstract 最近关于mobile network设计的研究已经证明了通道注意(例如&#xff0c;the Squee…

KVM虚拟机部署K8S重启后/etc/hosts内容丢失

前言 使用KVM开了虚拟机部署K8S&#xff0c;部署完成后重启&#xff0c;节点的pod等信息无法获取到&#xff0c;查看报错初步推测为域名解析失效&#xff0c;查看/etc/hosts后发现安装k8s时添加的内容全部消失 网上搜索一番之后发现了 如果直接修改 /etc/hosts 文件&#xff0…

什么是ETL?

ETL是一种数据集成过程&#xff0c;代表着“Extract, Transform, Load”&#xff0c;分别对应着数据抽取、数据转换和数据加载三个阶段。这个过程通常用于将数据从一个或多个数据源抽取出来&#xff0c;进行必要的处理和转换&#xff0c;最终加载到目标数据库、数据仓库或其他系…

【数据结构和算法】独一无二的出现次数

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 哈希类算法题注意事项 2.2 方法一&#xff1a;判断长度 2.3 方法二&#xff1a; set 判断 2.4 方法…

一个可以用于生产环境得PHP上传函数

上传表单 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>文件上传</title> </head> <body><h1>选择要上传的文件</h1><!-- 定义一个包含文件输入字段的表单 --…