当前位置: 首页 > article >正文

Nextjs15 - Streaming 流式传输是什么?

nextjs 官方文档(current branch 对应如下文档)

  • what-is-streaming
  • with-suspense

本专栏内容均可在Github:test_08/suspense_streaming 找到

一、传统 SSR

使用 SSR,用户需要完成一系列步骤才能看到页面并与之交互:

  • 首先,在服务器上获取给定页面的所有数据。
  • 然后服务器呈现该页面的 HTML
  • 页面的 HTMLCSSJavaScript 被发送到客户端。
  • 使用生成的 HTMLCSS 显示非交互式用户界面。
  • 最后,React 水合用户界面,使其具有交互性。

在这里插入图片描述

这些步骤是连续且阻塞的,这意味着服务器只有在获取所有数据后才能呈现页面的 HTML。而且,在客户端上,React 只有在下载完页面中所有组件的代码后才能补充 UI。

通过 ReactNext.jsSSR,可以尽快向用户显示非交互式页面,从而帮助提高感知的加载性能。

在这里插入图片描述

然而,它仍然很慢,因为在向用户显示页面之前需要完成服务器上的所有数据提取。

二、实现 Streaming 流式传输

1、通过 Suspense 标签实现

通过流式传输 ,您可以将页面的 HTML 分解为更小的块,然后逐步将这些块从服务器发送到客户端。

在这里插入图片描述

这使得页面的各个部分能够更快地显示,而无需等待所有数据加载后才能呈现任何 UI

流式传输与 React 的组件模型配合得很好,因为每个组件都可以被视为一个块。优先级较高的组件(例如产品信息)或不依赖数据的组件可以先发送(例如布局),React 可以更早地开始水化。优先级较低的组件(例如评论、相关产品)可以在其数据被获取后在同一服务器请求中发送。

在这里插入图片描述

<Suspense> 工作原理是包装一个执行异步操作(例如获取数据)的组件,在操作发生时显示后备 UI(例如骨架、微调器),然后在操作完成后交换组件。

见:app/page.tsx ,打开浏览器:http://localhost:3000/

我们可以看到,初始化所有组件均展示 loading,在 1、2、3s 后以此渲染 dom

import { Suspense } from "react";

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const PostFeed = async () => {
  await sleep(1000);
  return <div>PostFeed</div>;
};

const Weather = async () => {
  await sleep(2000);
  return <div>Weather</div>;
};

const User = async () => {
  await sleep(3000);
  return <div>User</div>;
};

export default function Home() {
  return (
    <div className="border-2 border-yellow-500 w-100 h-100">
      <Suspense fallback={<p>Loading feed...</p>}>
        <PostFeed />
      </Suspense>
      <Suspense fallback={<p>Loading weather...</p>}>
        <Weather />
      </Suspense>
      <Suspense fallback={<p>Loading user...</p>}>
        <User />
      </Suspense>
    </div>
  );
}

通过使用 Suspense,您可以获得以下好处:

  • 选择性水合 - React 根据用户交互确定首先使哪些组件具有交互的优先级。
  • 流式服务器渲染 - 从服务器逐步将 HTML 渲染到客户端。

Next.js 将等待 generateMetadata 中的数据提取完成后再将 UI 流式传输到客户端。这可确保流式传输响应的第一部分包含 <head> 标签,所以不会对 SEO 造成影响

2、通过 loading 页面组件 实现

见:app/website 目录下

其中,app/website/@about/page.tsx和app/website/@contact/page.tsx 文件内容如下

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const About = async () => {
  await sleep(2000);
  return <div>About</div>;
};

export default About;
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const Contact = async () => {
  await sleep(5000);
  return <div>Contact</div>;
};

export default Contact;

app/website/layout.tsx 文件内容如下,渲染@about@contact 两个平行路由

const Layout = ({
  children,
  about,
  contact,
}: {
  children: React.ReactNode;
  about: React.ReactNode;
  contact: React.ReactNode;
}) => {
  return (
    <div>
      <div>{about}</div>
      <div>{contact}</div>
      <div>{children}</div>
    </div>
  );
};

export default Layout;

效果见:

在这里插入图片描述


http://www.kler.cn/a/614020.html

相关文章:

  • 游戏引擎学习第181天
  • centos nginx添加域脚本
  • 代理模式(Proxy Pattern)实现与对比
  • 【AI插件开发】Notepad++插件开发实践:从基础交互到ScintillaCall集成
  • 基于MFC按钮逻辑
  • DQL语句-数据处理函数
  • 前端性能优化:深入解析哈希算法与TypeScript实践
  • C —— 指针和数组的面试题
  • Redis的缓存雪崩和缓存穿透的理解和如何避免
  • 后端开发基础:语言选择与 RESTful API 设计
  • C#使用用户名密码连接共享文件夹
  • 招聘面试季--金融系统常用的系统架构的特征
  • (C语言)指针运算 习题练习1.2(压轴难题)
  • python并发爬虫
  • SpringMVC的请求与响应
  • 如何使用Python爬虫获取1688商品评论?
  • pyspark学习rdd处理数据方法——学习记录
  • TDengine 中的系统信息统计
  • 【leetcode hot 100 45】跳跃游戏Ⅱ
  • SpringBoot 7 种实现 HTTP 调用的方式