前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React 18 如何提升应用性能

React 18 如何提升应用性能

作者头像
前端柒八九
发布2023-09-10 09:33:27
2930
发布2023-09-10 09:33:27
举报

❝我们趋行在人生这个亘古的旅途,在坎坷中奔跑,在挫折里涅槃,忧愁缠满全身,痛苦飘洒一地。 -- 《百年孤独》 ❞

大家好,我是「柒八九」

前言

最近,无意中看到一篇关于React 18的文章,翻看之后,发现很多东西都是React官网没有细讲的,并且发现有些点也是在实际开发中可以实践和应用的.

同时,配合我们之前讲的关于浏览器性能优化的文章,会对React的应用有一个更深的了解.所以就有了这篇文章.

这里做一个内容披露,因为下文中有很多关于React Server Components的知识细节,我们只是会做简短的说明,后面我们会有一篇单独针对它的文章.(已经在快马加鞭的在写了,不信你看)

好了,天不早了,干点正事哇。


1. 前置知识点

「前置知识点」,只是做一个概念的介绍,不会做深度解释。因为,这些概念在下面文章中会有出现,为了让行文更加的顺畅,所以将本该在文内的概念解释放到前面来。「如果大家对这些概念熟悉,可以直接忽略」

并发编程 VS 并行编程

我们在Rust并发中对这两个概念有过介绍,所以直接拿来主义了.

「并发编程」(Concurrent programming)和「并行编程」(Parallel Programming)都是指在计算机程序中「同时执行多个任务或操作的编程方式」,但它们在实现方式和目标上存在一些异同点。

并发编程

并发编程指的是在一个程序中同时进行多个任务,这些任务可以是「独立的,相互之间没有直接的依赖关系」。 ❞

在并发编程中,这些任务通常是「通过交替执行、时间片轮转或事件驱动的方式」来实现并行执行的假象。

并发编程的目标是「提高程序的效率、响应性和资源利用率」

并行编程

并行编程是指在「硬件级别上同时执行多个任务,利用计算机系统中的多个处理单元(例如多核处理器)或多台计算机来同时处理多个任务」。 ❞

在并行编程中,任务之间可以「有依赖关系,需要进行任务的分割和协调」

并行编程的目标是实现「更高的计算性能和吞吐量」


并发编程,代表程序的「不同部分相互独立的执行」,而 并行编程代表程序「不同部分于同时执行」。 ❞


主线程和长任务

当我们在浏览器中运行 JavaScript 时,JavaScript 引擎在一个单线程环境中执行代码,这通常被称为「主线程」

❝主线程除了执行 JavaScript 代码外,还负责处理其他任务,包括处理用户交互(如点击和键入)、处理网络事件、定时器、更新动画以及管理浏览器的回流(reflow)和重绘(repaint)等。 ❞

主线程负责逐个处理任务

「当一个任务正在被处理时,所有其他任务必须等待」。虽然浏览器可以顺利执行小型任务以提供流畅的用户体验,但长时间的任务可能会带来问题,因为它们会阻塞其他任务的处理。


❝任何执行时间超过 50 毫秒的任务被视为「长任务」。 ❞

这个 50 毫秒的基准是基于设备必须每 16 毫秒(60 帧每秒)创建一个新帧以保持流畅的视觉体验的事实。然而,设备还必须执行其他任务,比如响应用户输入和执行 JavaScript

这个 50 毫秒的基准允许设备将资源分配给渲染帧和执行其他任务,并「为设备提供额外的约 33.33 毫秒的时间来执行其他任务」,同时保持流畅的视觉体验。

关于为何以50 毫秒为基准,我们在之前的浏览器之性能指标-TBT中介绍了 RAIL 性能模型. 这里就不再过多介绍.


为了保持最佳性能,重要的是要尽量减少长任务的数量。为了衡量我们网站的性能,有两个指标可以衡量长任务对应用程序性能的影响:总阻塞时间(Total Blocking Time,简称 TBT)和与下一次绘制的交互(Interaction to Next Paint,简称 INP)。

TBT 是一个重要的指标,它衡量了从首次内容绘制(First Contentful Paint,简称 FCP)到可交互时间(Time to Interactive,简称 TTI)之间的时间。TBT「长于 50 毫秒的任务执行所花费的时间之和」

如上图所示,TBT45 毫秒,因为在 TTI 之前有两个任务的执行时间超过了 50 毫秒的阈值,分别超出了 30 毫秒15 毫秒

❝总阻塞时间是这些数值的累加:30 毫秒 + 15 毫秒 = 45 毫秒

INP是一个新的Core Web Vitals 指标,它衡量了从用户首次与页面进行交互(例如点击按钮)到该交互在屏幕上可见的时间;即下一次绘制的时间。这个指标对于包含许多用户交互的页面尤为重要。它通过累积用户在当前访问期间的所有 INP 测量值,并返回最差的分数来进行衡量。

INP为 250 毫秒,因为这是最高的测量可见延迟。


React_Fiber

既然聊到了React 18,那肯定绕不过去,React Fiber的东西,而针对Fiber的介绍,我们之前就有对应的文章.

  1. React_Fiber(上)
  2. React_Fiber(下)

在这两篇文章中,会出现React 元素(虚拟DOM)/Fiber 节点/副作用/渲染算法/调和机制. 由于这些概念都很杂很多,如果想单独了解,请自行查找,这里不做解释了.


客户端渲染(CSR) 和服务端渲染(SSR)

CSR

❝页面托管服务器只需要对页面的「访问请求响应」一个如下的「空页面」

代码语言:javascript
复制
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <!-- metas -->
    <title></title>
    <link rel="shortcut icon" href="xxx.png" />
    <link rel="stylesheet" href="xxx.css" />
  </head>
  <body>
    <div id="root"><!-- page content --></div>
    <script src="xxx/filterXss.min.js"></script>
    <script src="xxx/x.chunk.js"></script>
    <script src="xxx/main.chunk.js"></script>
  </body>
</html>

页面中留出一个「用于填充渲染内容的视图节点」 (div#root),并插入指向项目「编译压缩后」

  • JS Bundle 文件的 script 节点
  • 指向 CSS 文件的 link.stylesheet 节点等。

浏览器接收到这样的文档响应之后,会「根据文档内的链接加载脚本与样式资源」,并完成以下几方面主要工作:

  1. 「执行脚本」
  2. 进行「网络访问以获取在线数据」
  3. 使用 DOM API 「更新页面结构」
  4. 「绑定交互事件」
  5. 「注入样式」

其中,「执行脚本」就需要安装每个前端框架的内置方法,将JS代码生成对应的Virtual DOM,然后在通过浏览器内置API将其转换为DOM, 然后才会进行事件的绑定。


SSR


2. 传统React渲染模式

❝在 React 中,视觉更新分为两个阶段:「渲染阶段」「提交阶段」。 ❞

「渲染阶段」是一个「纯计算阶段」,其中 React元素与现有的 DOM 进行对比(也就是调和)。这个阶段涉及创建一个「新的 React 元素树」,也称为虚拟 DOM,它实质上是「实际 DOM 的轻量级内存表示」

❝在渲染阶段,React 计算当前 DOM新的 React 组件树之间的差异,并准备必要的更新。 ❞

「渲染阶段之后是提交阶段」。在这个阶段,React 将在渲染阶段计算得到的更新应用到「实际 DOM 上」。这涉及创建更新删除 DOM 节点,以反映新的 React 组件树


❝在传统的「同步渲染」中,React 对组件树中的「所有元素赋予相同的优先级」。 ❞

当组件树被渲染时,无论是在初始渲染还是状态更新时,React 会在一个「不可中断的单一任务中渲染整个树」,之后将其提交到 DOM 中,以在屏幕上更新组件的可视化效果。

同步渲染是一种all-or-nothing的操作,确保开始渲染的组件将始终完成渲染。根据组件的复杂性,渲染阶段可能「需要一段时间才能完成」。在此期间,「主线程被阻塞」,意味着用户在尝试与应用程序交互时会遇到无响应的用户界面,直到 React 完成渲染并将结果提交到 DOM 中。


假设存在这样的场景。有一个文本输入框和一个包含大量城市的列表,列表根据文本输入框当前的值进行过滤。在同步渲染中,React 会在每次键入时重新渲染 CitiesList 组件。这是一种非常昂贵的计算,因为列表包含成千上万个城市,因此在键入和在文本输入框中看到反映的过程中存在明显的视觉反馈延迟。

index.js

代码语言:javascript
复制
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import App from "./App";

const rootElement = document.getElementById("root");

ReactDOM.render(<StrictMode><App /></StrictMode>,  rootElement);

App.js

代码语言:javascript
复制
import React, { useState } from "react";
import CityList from "./CityList";

export default function SearchCities() {
  const [text, setText] = useState("太原");

   return (    
      <main>          
          <input type="text" onChange={(e) => setText(e.target.value) }   />      
          <CityList searchQuery={text} />    
      </main>  
     );
};

CityList.js

代码语言:javascript
复制
import cities from "cities-list";
import React, { useEffect, useState } from "react";
const citiesList = Object.keys(cities);

const CityList = React.memo(({ searchQuery }) => {
  const [filteredCities, setCities] = useState([]);

  useEffect(() => {
    if (!searchQuery) return;

    setCities(() =>
      citiesList.filter((x) =>
         x.toLowerCase().startsWith(searchQuery.toLowerCase())
      )
    );
   }, [searchQuery]);

  return (
     <ul>
       {filteredCities.map((city) => (
         <li key={city}>
           {city}
        </li>
       ))}
    </ul>
    )
});

export default CityList;

❝如果我们使用像 MacBook 这样的高端设备,我们可能希望将 CPU 性能降低 4 倍,以模拟低端设备的情况。我们可以在开发者工具中找到这个设置,路径是 Devtools > Performance > ⚙️ > CPU

当我们查看性能选项卡时,可以看到每次输入都会发生长时间的任务,这是我们不能容忍的。

❝被标记为红色角标的任务被认为是长任务。请注意总阻塞时间为4425.40毫秒。 ❞

在这种情况下,React 开发者通常会使用像 debounce 这样的第三方库来延迟渲染,但并没有内置的解决方案。


React 18 引入了一个新的并发渲染器,它「在后台运行」。这个渲染器为我们提供了一些方法来「标记某些渲染为非紧急渲染」

❝当渲染低优先级组件(标记为红色)时,React「让出主线程,以便检查是否有更重要的任务需要处理」。 ❞

在这种情况下,React「每隔 5 毫秒让出主线程」,以查看是否有更重要的任务需要处理,比如用户输入,甚至是渲染其他 React 组件的状态更新,这些任务在当前时刻对用户体验更重要。「通过持续地让出主线程,React 能够使这些渲染成为非阻塞的,并优先处理更重要的任务」。这样可以改善用户体验并提高应用程序的性能。

❝与每次渲染一个「单一的不可中断任务」不同,新的并发渲染器在渲染低优先级组件时,「在每个 5 毫秒的间隔内将控制权交还给主线程」。 ❞

此外,并发渲染器能够在「后台“并发”地渲染多个版本的组件树,而不立即提交结果」

与同步渲染是一种all-or-nothing的计算方式不同, 并发渲染器允许 React 「暂停」「恢复」渲染一个或多个组件树,以实现最优化的用户体验。这样的方式可以提高应用程序的性能,并确保用户界面的流畅和响应性。

当某个重要任务出现时,React 可以中断当前的渲染,转而处理该任务,然后在合适的时候继续渲染,避免了阻塞主线程和UI无响应的情况,从而提升了整体的渲染效率。

React根据用户交互暂停当前的渲染,「强制它优先渲染另一个更新」。 ❞

借助并发特性,React 可以根据外部事件(如用户交互)暂停恢复组件的渲染。当用户开始与 ComponentTwo 进行交互时,React 暂停当前的渲染,「优先渲染」 ComponentTwo,然后再继续渲染 ComponentOne


3. 过渡

我们可以通过使用 useTransition 钩子提供的 startTransition 函数「将更新标记为非紧急」。这是一个强大的新功能,允许我们「将某些状态更新标记为过渡(transitions),表示它们可能会导致视觉变化,如果它们同步渲染,可能会影响用户体验」

❝通过将「状态更新」包装在 startTransition 中,我们可以告诉 React 我们可以「推迟」「中断渲染」,以优先处理更重要的任务,以保持当前的用户界面的交互性。 ❞

这样的做法可以提高应用程序的性能,并确保用户界面的流畅和响应性。

代码语言:javascript
复制
import { useTransition } from "react";

function Button() {
  const [isPending, startTransition] = useTransition();

  return (
    <button 
      onClick={() => {
        // 紧急更新
        urgentUpdate();
+        startTransition(() => {
+          nonUrgentUpdate() // 非紧急更新
+        })
      }}
    >...</button>
  )
}

当过渡开始时, 并发渲染器会在「后台准备新的组件树」。一旦渲染完成,它会「将结果保存在内存中」,直到 React 调度程序能够高效地更新 DOM 来反映新的状态。

❝这个时机可能是当浏览器处于「空闲状态」,并且没有更高优先级的任务(比如用户交互)在等待执行时。 ❞

在这个时机,React 将会将新的渲染结果提交到 DOM,更新用户界面,以确保更新的呈现是流畅的,并避免对用户体验产生不良影响。


使用过渡功能对于 CitiesList 示例非常适合。不必在每次输入时直接更新传递给 searchQuery 参数的值,这样会导致每次键入都触发同步渲染调用。相反,我们可以将状态分成两个值,并在 searchQuery 的状态更新中使用 startTransition

这告诉 React,状态更新可能会导致对用户造成视觉上的干扰,因此 React 应该尽力保持当前用户界面的交互性,同时「在后台准备新的状态,而不立即提交更新」。通过这样的方式,React 可以更加智能地管理渲染优先级,优化用户体验,确保用户界面的流畅和响应性。

代码语言:javascript
复制
import React, { useState, useTransition } from "react";
import CityList from "./CityList";

export default function SearchCities() {
  const [text, setText] = useState("太原");
  const [searchQuery, setSearchQuery] = useState(text);
+  const [isPending, startTransition] = useTransition();

   return (    
      <main>      
          <input  
              type="text" 
              value={text}
              onChange={(e) => {
                 setText(e.target.value)
+                 // 减低该操作的,渲染优先级
                 startTransition(() => {
                    setSearchQuery(e.target.value)
                 })
             }}  />      
          <CityList searchQuery={searchQuery} />    
      </main>  
     );
};

现在,当我们在输入框中输入时,用户输入保持流畅,在按键之间没有任何视觉延迟出现。这是因为文本状态仍然同步更新,输入框使用该状态作为其值。

「后台」React 在每次输入时开始渲染新的组件树。但是,与同步任务的all-or-nothing不同,React 开始在「内存中准备新版本的组件树,同时当前用户界面(显示“旧”状态)仍然对进一步的用户输入保持响应」

查看性能选项卡,将状态更新包装在 startTransition 中显著「减少了长时间任务的数量和总阻塞时间」,相比没有使用过渡的实现的性能图表。这表明使用过渡功能对于优化应用程序的性能和用户体验是非常有效的

❝性能选项卡显示长任务数量和总阻塞时间明显减少了。 ❞

过渡(transitions)React 渲染模型中的一个基本变革,使 React 能够「同时渲染多个版本的用户界面,并在不同任务之间管理优先级」。这使得用户体验更加流畅和响应,尤其在处理高频更新CPU 密集的渲染任务时。过渡功能的引入为 React 应用程序的性能和交互性带来了显著的提升。


4. React Server Components

React Server Components(简称RSC) 是 React 18 中的「实验性功能」,但是,有些框架已经决定适配该功能.

传统上,React 提供了几种主要的渲染方式。

客户端渲染CSR

完全在客户端渲染所有内容

服务端渲染SSR

在服务器上将组件树渲染为 HTML,并将这个静态 HTML 与 JavaScript 捆绑包一起发送到客户端,用于在「客户端进行组件的挂载」

❝这两种方法都依赖于一个事实,即同步的 React 渲染器需要「使用已经传递的 JavaScript 捆绑包在客户端重新构建组件树,尽管这个组件树在服务器上已经可用」。 ❞

CSRSSR中,都需要通过 JavaScript 捆绑包在客户端重建组件树。

  • CSR 中,「整个渲染过程发生在客户端的浏览器中」JavaScript 捆绑包负责生成组件树和渲染用户界面。
  • SSR 中,服务器预先将组件树渲染为 HTML 并将其与 JavaScript 捆绑包一起发送到客户端,然后客户端接管渲染过程并挂载组件,使其成为可交互。

❝在这两种情况下,「组件树都需要在客户端重新构建」,尽管在服务器上已经有一个可用的组件树。这可能导致加载时间增加,并潜在地影响性能和用户体验。 ❞


RSC 允许 React 将实际「序列化的组件树发送给客户端」。客户端的 React 渲染器理解这种格式,并使用它来高效地重构 React 组件树,而「无需发送 HTML 文件或 JavaScript 捆绑包」

我们可以通过将 react-server-dom-webpack/serverrenderToPipeableStream 方法与 react-dom/clientcreateRoot 方法结合使用来采用这种新的渲染模式。

  • react-server-dom-webpack/serverrenderToPipeableStream 方法用于「在服务器端将组件树序列化为可流式传输的格式」,然后将其发送给客户端。
  • react-dom/clientcreateRoot 方法用于「在客户端接收并高效地重构从服务器端传输的组件树」,从而完成渲染。

server/index.cjs

代码语言:javascript
复制
const express = require('express');
const {renderToPipeableStream} = require('react-server-dom-webpack/server');
const ReactApp = require('../src/App').default;

const PORT = process.env.PORT || 4000;
const app = express();

app.listen(PORT, () => {
  console.log(`Listening at ${PORT}...`);
});

app.get('/rsc', async function(req, res) {
  const {pipe} = renderToPipeableStream(
    React.createElement(ReactApp),
  );

  return pipe(res);
});

src/index.js

代码语言:javascript
复制
"use client";
import { createRoot } from 'react-dom/client';
import { createFromFetch } from 'react-server-dom-webpack/client';
export function Index() {
  ...
  return createFromFetch(fetch('/rsc'));
}
const root = createRoot(document.getElementById('root'));
root.render(<Index />);

默认情况下,React 不会对 RSC 进行挂载。这些组件「不应该使用任何客户端属性」,比如访问 window 对象,或使用像 useStateuseEffect 这样的钩子。

要将一个组件及其导入添加到 JavaScript 捆绑包中,并将其发送到客户端,从而使其具有交互性,可以在文件的顶部使用 use client 捆绑器指令。这会告诉捆绑器将此组件及其导入添加到客户端捆绑包,并告诉 React 在客户端进行挂载以增加交互性。这样的组件被称为客户端组件(Client Components)。

❝注意:不同的框架实现可能会有所不同。例如,Next.js 会在服务器上预渲染客户端组件为 HTML,类似于传统的 SSR 方法。然而,默认情况下,客户端组件的渲染方式类似于 CSR 方法。 ❞

确实,当使用客户端组件时,优化捆绑包大小是开发者的责任。开发者可以通过以下方式实现优化:

  1. 确保只有交互组件的最终子节点定义了 use client 指令。这可能需要对一些组件进行解耦。
  2. 通过 props 传递组件树,而不是直接导入它们。这使得 React 可以将子组件渲染为 RSC,而无需将它们添加到客户端捆绑包中。这样可以减少客户端捆绑包的大小。

5. Suspence

另一个重要的新并发功能是 Suspense。虽然 Suspense 并不是完全新的,因为它在 React 16 中用于 React.lazy「代码拆分」,但在 React 18 中引入了新的功能,「将 Suspense 扩展到数据获取领域」

❝使用 Suspense,我们可以「延迟组件的渲染」,直到满足特定条件,比如从远程源加载数据。同时,我们可以渲染一个占位组件,表示该组件仍在加载中。 ❞

通过声明式地定义加载状态,我们减少了对条件渲染逻辑的需求。将 SuspenseRSC结合使用,我们可以「直接访问服务器端的数据源」,而无需额外的 API 端点,比如数据库或文件系统。

代码语言:javascript
复制
async function BlogPosts() {
  const posts = await db.posts.findAll();
  return '...';
}
 
export default function Page() {
  return (
    <Suspense fallback={<Skeleton />}>
      <BlogPosts />
    </Suspense>
  )
}

❝使用 RSCSuspense 的结合可以无缝地工作,这允许我们「在组件加载过程中定义加载状态」。 ❞

Suspense 的真正威力在于它与 React「并发特性深度整合」。当一个组件被暂停(例如因为它仍在等待数据加载),React 并不会无所作为,直到组件接收到数据为止。相反,它会暂停被挂起组件的渲染,并将重点转向其他任务。

这种行为使得 React 能够「更加智能地管理任务优先级」,优化应用程序的性能和用户体验。当一个组件暂停时,React 会继续处理其他重要任务,如用户交互或渲染其他已准备好的组件。「一旦挂起的组件获取到所需的数据,React 就会恢复其渲染,保证用户界面的流畅和响应」。这种能力使得 Suspense 与并发特性的结合能够实现更高效的数据加载和渲染过程,提升应用程序的性能和用户体验。

在此期间,我们可以告诉 React 渲染一个「备用的用户界面」,以指示该组件仍在加载中。一旦等待的数据可用,React 就可以无缝地以中断的方式恢复先前被暂停的组件渲染。

React 还可以「根据用户交互重新设置组件的优先级」。例如,当用户与一个当前未被渲染的挂起组件进行交互时,React 会暂停正在进行的渲染,并将用户正在交互的组件设为优先级。 ❞

通过这种方式,React 能够更加智能地管理任务的优先级,「根据用户交互动态地调整组件的渲染优先级」,从而提供更好的用户体验。Suspense 与并发特性的结合为 React 提供了强大的渲染控制能力,使得应用程序的渲染过程更加灵活高效,同时保证了用户界面的流畅性和响应性。

一旦准备好,React 将其提交到 DOM,并恢复先前的渲染。这确保了用户交互的优先级,并使用户界面保持响应,并随着用户输入实时更新。

SuspenseRSC 的流式格式的结合「允许高优先级的更新在准备好后立即发送到客户端,而无需等待较低优先级的渲染任务完成」。这使得客户端能够更早地开始处理数据,并通过逐步以非阻塞的方式展示内容,提供更流畅的用户体验。

这种可中断的渲染机制与 Suspense 处理异步操作的能力相结合,为用户提供了更加流畅和以用户为中心的体验,特别适用于具有大量数据获取需求的复杂应用程序。

通过这些并发特性,React 能够更加智能地管理任务的优先级,实现更高效的渲染和数据处理过程,为用户提供更好的交互体验,使得应用程序在处理异步操作时更加平滑和高效。


6. 数据获取

除了渲染更新外,React 18 还引入了一种新的 API 来「高效地获取数据并对结果进行记忆」

React 18 现在有一个 cache 函数,它可以「缓存函数调用的结果」。如果在同一次渲染过程中使用相同的参数再次调用相同的函数,它将使用记忆化的值,而无需再次执行该函数。 ❞

代码语言:javascript
复制
import { cache } from 'react'
 
export const getUser = cache(async (id) => {
  const user = await db.user.findUnique({ id })
  return user;
})

getUser(1)
getUser(1) // 传人的参数相同,使用缓存的数据

「在数据获取的 fetch 调用中,React 18 现在默认包含了类似的缓存机制,无需使用 cache 函数」。这有助于减少在单个渲染过程中的网络请求次数,从而提高应用程序的性能并降低 API 成本。

代码语言:javascript
复制
export const fetchPost = (id) => {
  const res = await fetch(`https://.../posts/${id}`);
  const data = await res.json();
  return { post: data.post } 
}

fetchPost(1)
fetchPost(1) //  传人的参数相同,使用缓存的数据

这些特性在使用 RSC时非常有用,因为它们无法访问 Context API。cachefetch 的自动缓存行为允许将单个函数从全局模块导出,并在整个应用程序中重复使用它,这样可以更加高效地处理数据获取和记忆化。这样的设计使得在 RSC中处理数据获取变得更加简便和高效。

代码语言:javascript
复制
async function fetchBlogPost(id) {
  const res = await fetch(`/api/posts/${id}`);
  return res.json();
} 

async function BlogPostLayout() {
  const post = await fetchBlogPost('123');
  return '...'
}
async function BlogPostContent() {
   // 请求参数和之前的一样,返回缓存后的值
  const post = await fetchBlogPost('123'); 
  return '...'
}

export default function Page() {
  return (
    <BlogPostLayout>
      <BlogPostContent />
    </BlogPostLayout>
  )
}

总结

总体而言,React 18 的最新特性在许多方面都提高了性能。

  • 使用 Concurrent,渲染过程可以被暂停、延迟或甚至放弃。这意味着即使正在进行大规模的渲染任务,用户界面仍可以立即响应用户输入。
  • Transitions API 允许在数据获取或屏幕切换期间实现更平滑的过渡,而不会阻塞用户输入。
  • RSC 允许开发者构建在服务器和客户端上都可用的组件,将客户端应用程序的交互性与传统服务器渲染的性能相结合,而无需付出 hydration 的代价。
  • 扩展的 Suspense 功能通过允许应用程序的部分内容在其他需要更长时间获取数据的部分之前渲染,提高了加载性能。

这些新特性共同为 React 应用程序带来了更高效和更流畅的用户体验。


后记

「分享是一种态度」

参考资料:

  1. Rust并发
  2. 浏览器之性能指标-TBT
  3. react 18 新特性
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端柒八九 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 1. 前置知识点
    • 并发编程 VS 并行编程
      • 并发编程
      • 并行编程
    • 主线程和长任务
      • React_Fiber
        • 客户端渲染(CSR) 和服务端渲染(SSR)
          • CSR
          • SSR
          • index.js
          • App.js
          • CityList.js
          • 客户端渲染CSR
          • 服务端渲染SSR
          • server/index.cjs
          • src/index.js
      • 2. 传统React渲染模式
      • 3. 过渡
      • 4. React Server Components
      • 5. Suspence
      • 6. 数据获取
      • 总结
      • 后记
      相关产品与服务
      云开发 CLI 工具
      云开发 CLI 工具(Cloudbase CLI Devtools,CCLID)是云开发官方指定的 CLI 工具,可以帮助开发者快速构建 Serverless 应用。CLI 工具提供能力包括文件储存的管理、云函数的部署、模板项目的创建、HTTP Service、静态网站托管等,您可以专注于编码,无需在平台中切换各类配置。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档