首页 > 其他分享 >如何使用流式渲染技术提升用户体验

如何使用流式渲染技术提升用户体验

时间:2024-12-04 10:31:38浏览次数:13  
标签:const rs 渲染 流式 体验 async new

什么是流式渲染?

流式渲染主要思想是将HTML文档分块(chunk)并逐块发送到客户端,而不是等待整个页面完全生成后再发送。

流式渲染不是什么新鲜的技术。早在90年代,网页浏览器就已经开始使用这种方式来处理HTML文档。

在 SPA (单页应用)流行的时代,由于 SPA 的核心是客户端动态地渲染内容,流式渲染没有得到太多关注。如今,随着服务端渲染相关技术的成熟,流式渲染成为可以显著提升首屏加载性能的利器。

素材来源于文章

Node.js 实现简单流式渲染

HTTP is a first-class citizen in Node.js, designed with streaming and low latency in mind. This makes Node.js well suited for the foundation of a web library or framework.

HTTP 是 Node.js 中的一等公民,其设计时考虑到了流式传输和低延迟。这使得 Node.js 非常适合作为 Web 库或框架的基础。

———— Node.js官网

Node.js 在设计之初就考虑到了流式传输数据,考虑如下代码:

const Koa = require('koa');
const app = new Koa();

// 假设数据需要 5 秒的时间来获取
renderAsyncString = async () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('<h1>Hello World</h1>');
    }, 5000);
  })
}

app.use(async (ctx, next) => {
  ctx.type = 'html';
  ctx.body = await renderAsyncString();
  await next();
});

app.listen(3000, () => {
  console.log('App is listening on port 3000');
});

这是一个简化的业务场景,运行起来后,会在5秒的白屏后显示一段 hello world 文字。

没有用户会喜欢一个会白屏5秒的网页!在 web.dev 对 TTFB 的介绍中,加载第一个字节的时间应该在 800ms 内才是良好的 web 网站服务。

我们可以利用流式渲染技术来改善这一点,先通过渲染一个 loading 或者骨架屏之类的东西来改善用户体验。查看改进后的代码:

const Koa = require('koa');
const app = new Koa();
const Stream = require('stream');

// 假设数据需要 5 秒的时间来获取
renderAsyncString = async () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('<h1>Hello World</h1>');
    }, 5000);
  })
}

app.use(async (ctx, next) => {
  const rs = new Stream.Readable();
  rs._read = () => {};
  ctx.type = 'html';
  rs.push('<h1>loading...</h1>');
  ctx.body = rs;
  renderAsyncString().then((string) => {
    rs.push(`<script>
      document.querySelector('h1').innerHTML = '${string}';
    </script>`);
  })
});

app.listen(3000, () => {
  console.log('App is listening on port 3000');
});

使用流式渲染后,这个页面最初显示 "loading...",然后在 5 秒后更新为 "Hello World"。

需要注意的是:Safari 浏览器对于何时触发流式传输可能有一些限制(以下内容未找到官方说明,通过实践总结得到):

  • 传输的 chunk 需大于 512 字节

  • 传输的内容需能够在屏幕上实际渲染,例如传输 <div style="display:none;">...</div> 可能是不生效的。

声明式 Shadow DOM,不依赖 javascript 实现

上面的代码中,我们用到了一些 javascript,本质上我们需要预先渲染一部分 html 标签作为占位,之后在用新的 html 标签去替换他们。这用 javascript 很好实现,如果我们禁用了 javascript 呢?

这可能需要一些 Shadow DOM 的技巧!很多组件化设计前端框架都有 slot 的概念,在 Shadow DOM 中也提供了 slot 标签,可以用于创建可插入的 Web Components。在 chrome 111 版本以上,我们可以使用声明式 Shadow DOM,不依赖 javascript,在服务器端使用 shadow DOM。一个声明式 Shadow DOM 的例子:

    <template shadowrootmode="open">
      <header>Header</header>
      <main>
        <slot name="hole"></slot>
      </main>
      <footer>Footer</footer>
    </template>
  
    <div slot="hole">插入一段文字!</div>

我们的文字被插入在了 slot 标签中,利用声明式 Shadow DOM,我们可以改写上面的例子:

const Koa = require('koa');
const app = new Koa();
const Stream = require('stream');

// 假设数据需要 5 秒的时间来获取
renderAsyncString = async () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('<h1>Hello World</h1>');
    }, 5000);
  })
}

app.use(async (ctx, next) => {
  const rs = new Stream.Readable();
  rs._read = () => {};
  ctx.type = 'html';
  rs.push(`
  <template shadowrootmode="open">
    <slot name="hole"><h1>loading</h1></slot>
  </template>
  `);
  ctx.body = rs;
  renderAsyncString().then((string) => {
    rs.push(`<h1 slot="hole">${string}</h1>`);
    rs.push(null);
  })
});

app.listen(3000, () => {
  console.log('App is listening on port 3000');
});

运行这段代码,和之前的代码结果完全一致,不同的,当我们禁用掉浏览器的 javascript,代码也一样正常运行!

声明式 Shadow DOM 是一个比较新的特性,可以在这篇文档中看到更多内容。

react 实现流式渲染

我们换个视角看看 react,react 18 之后在框架层面上支持了流式渲染, 下面是使用 nextjs 改写上面的代码:


import { Suspense } from 'react'


const renderAsyncString = async () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello World!');
}, 5000);
})
}

async function Main() {
const string = await renderAsyncString();
return <h1>{string}</h1>
}

export default async function App() {
return (
<Suspense fallback={<h1>loading...</h1>} >
<Main />
</Suspense>
)
}

运行这段代码,和之前的代码结果完全一致,同样也不需要运行任何客户端的 javascript 代码。

关于 react 的流式渲染在这里能看到官方技术层面上的解释。本文作为对于流式渲染的概览,不作更细致的讲解。

总结

本文从理论上探讨了流式渲染相关实现方案,理论上,流式渲染很简单。HTTP 标准和 Node.js 很早之前就支持了这一特性。但在工程实践中,它很复杂。例如对于 react 来说,流式渲染不仅仅需要 react 作为 UI 来支持,也需要借助 nextjs 这种元框架(meta framework)提供服务端的能力。

标签:const,rs,渲染,流式,体验,async,new
From: https://blog.csdn.net/2301_78659329/article/details/144231372

相关文章

  • 说说页面中字体渲染规则是怎样的?会有哪些因素影响字体的渲染?
    网页中字体的渲染是一个复杂的过程,受到多种因素的影响。总的来说,浏览器会根据一系列规则和设置来决定如何显示文本。以下是主要的渲染规则和影响因素:渲染规则:CSS继承和层叠:字体样式可以继承自父元素,也可以被子元素的样式覆盖。CSS的层叠规则决定了哪个样式最终生效。fon......
  • 基于物理的渲染(4):Disney 原则
    1背景​​  2010年提出的PBR光照模型存在包含大量复杂而晦涩的物理参数,不利于美术人员理解、使用和快速产出等问题,2012年disney发表《Physically-basedshadingatDisney》,提出了Disney原则的BRDF,在行业内制造了一场基于物理的渲染革命。之后主流游戏引擎都开始从传统的渲......
  • 中安证件OCR识别技术助力鸿蒙生态:智能化证件识别新体验
    在数字化和智能化的浪潮中,伴随国产化战略的深入推进,国产操作系统和软件生态的建设逐渐走向成熟。鸿蒙操作系统(HarmonyOSNext)作为华为推出的重要操作系统,凭借其开放、灵活和高效的特点,正在加速在多个领域的普及和应用。特别是在智能识别和人工智能技术的支持下,鸿蒙系统在各行各......
  • PWA如何改变我们的移动体验?
    PWA(ProgressiveWebApps)通过结合Web和原生应用的优势,显著改变了我们的移动体验。它们提供了一种更便捷、更快速、更engaging的方式来访问和使用网络内容,弥合了Web和原生应用之间的差距。以下是PWA如何改变移动体验的一些关键方面:1.可发现性和可访问性:无需应用商店:......
  • 低配电脑也能轻松渲染珠宝动画:云渲染技术的应用
    珠宝设计中,动画渲染至关重要,但高配置需求常成障碍。云渲染技术解决了这一问题,让低配电脑也能轻松完成高质量渲染,释放设计师的创意潜力。本文将探讨云渲染如何革新珠宝设计行业。一、渲染配置要求在珠宝设计渲染的过程中,硬件配置对于实现高效和高质量的渲染至关重要。其中,CPU(中......
  • 释放超凡性能,打造鸿蒙原生游戏卓越体验
    11月26日在华为Mate品牌盛典上,全新Mate70系列及多款全场景新品正式亮相。在游戏领域,HarmonyOSNEXT加持下游戏的性能得到充分释放。HarmonyOSSDK为开发者提供了软硬协同的系统级图形加速解决方案------GraphicsAccelerateKit(图形加速服务),帮助游戏应用快速集成超帧、GTX自适应稳......
  • 网站架构优化:构建高效、用户友好的在线体验
    在数字化时代,网站不仅是企业展示品牌形象和提供服务的窗口,更是与用户建立联系、促进转化的关键平台。一个精心设计的网站架构能够显著提升用户体验,增强搜索引擎的抓取效率,从而推动业务增长。本文将深入探讨网站架构优化的重要性、原则及实施策略,帮助您构建一个高效、用户友好......
  • ai大模型流式输出------基于SSE协议的长连接实现ax
    传统的http1.0请求开发,已经满足了我们日常的web开发。一般请求就像下图这样子,客服端发起一个请求(触发),服务端做出一个响应(动作):有时会有诸如实时刷新,实时显示的场景,我们往往是客户端定时发起请求,不断的尝试获取最新的数据。但是每次请求都会创建并释放一个新的连接,这样对于需要频繁......
  • ai大模型流式输出------基于SSE协议的长连接实现
    传统的http1.0请求开发,已经满足了我们日常的web开发。一般请求就像下图这样子,客服端发起一个请求(触发),服务端做出一个响应(动作):有时会有诸如实时刷新,实时显示的场景,我们往往是客户端定时发起请求,不断的尝试获取最新的数据。但是每次请求都会创建并释放一个新的连接,这样对于需要频繁......
  • 说下你对沉浸式体验的理解
    在前端开发语境下,沉浸式体验指的是一种深度吸引用户、让用户感觉身临其境的网页或应用体验。它试图模糊现实世界和数字世界之间的界限,让用户专注于当前的内容和交互,而忽略周围的环境。要实现沉浸式体验,前端开发需要关注以下几个方面:视觉呈现:全屏体验:隐藏浏览器界面元素(......