当前位置:首页 > 科技  > 软件

我们一起聊聊如何通过流式渲染提升用户体验?

来源: 责编: 时间:2024-06-27 17:13:30 194观看
导读什么是流式渲染?流式渲染的核心理念是将 HTML 文档分割成小块(chunk),并逐步地发送给客户端,而非等待整个页面完整生成后再进行传输。这种方式能够极大地提升用户的初始加载体验,特别是在网络条件不佳或者页面内容复杂的情

什么是流式渲染?

流式渲染的核心理念是将 HTML 文档分割成小块(chunk),并逐步地发送给客户端,而非等待整个页面完整生成后再进行传输。这种方式能够极大地提升用户的初始加载体验,特别是在网络条件不佳或者页面内容复杂的情况下。BxA28资讯网——每日最新资讯28at.com

流式渲染并非新兴技术,早在 90 年代,网页浏览器就已开始运用这种模式来处理 HTML 文档。不过,在 SPA(单页应用)大行其道的时期,由于其核心在于客户端动态渲染内容,流式渲染未能引起广泛关注。然而,现今随着服务端渲染技术的日臻成熟,流式渲染已成为显著优化首屏加载性能的有力手段。BxA28资讯网——每日最新资讯28at.com

Node.js 实现简单流式渲染

HTTP 是 Node.js 中的一等公民,其在设计时就充分考虑了流式传输和低延迟特性。这使得 Node.js 极为适合作为 Web 库或框架的构建基础。 ———— Node.js 官网BxA28资讯网——每日最新资讯28at.com

Node.js 从设计之初就将流式传输数据纳入考量,以下是一个简单的示例代码:BxA28资讯网——每日最新资讯28at.com

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"这段文字。BxA28资讯网——每日最新资讯28at.com

毫无疑问,没有用户会愿意忍受一个长达 5 秒的白屏网页!在 web.dev[1] 对于 TTFB(Time To First Byte,首字节时间)的介绍中提到,加载第一个字节的时间应当控制在 800ms 以内,才能称得上是优质的 Web 网站服务。BxA28资讯网——每日最新资讯28at.com

为了改善这种情况,我们可以借助流式渲染技术。比如,先向用户呈现一个加载中的提示或者骨架屏,以此来优化用户体验。下面是改进后的代码:BxA28资讯网——每日最新资讯28at.com

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"。BxA28资讯网——每日最新资讯28at.com

需要特别注意的是,Safari 浏览器对于何时触发流式传输可能存在一些限制(以下内容未找到官方说明,而是通过实践总结得出):BxA28资讯网——每日最新资讯28at.com

  • 传输的 chunk 大小需大于 512 字节。若小于此值,可能无法有效触发流式传输,影响用户体验。
  • 传输的内容必须能够在屏幕上实际渲染。例如,传输<div style="display:none;">...</div>这样隐藏的内容可能是无效的,无法实现流式渲染的预期效果。

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

在上述的代码中,我们运用了一定的 JavaScript 代码。本质上,我们需要预先渲染一部分 HTML 标签作为占位,随后再用新的 HTML 标签对其进行替换。使用 JavaScript 来实现这一过程相对容易,但如果禁用了 JavaScript 呢?BxA28资讯网——每日最新资讯28at.com

这就可能需要借助一些 Shadow DOM[2] 的技巧!众多组件化设计的前端框架都包含了 slot(插槽)的概念,在 Shadow DOM 中也提供了 slot 标签,其可用于创建可插入的 Web Components。在 Chrome 111 及以上版本中,我们能够使用声明式 Shadow DOM,无需依赖 JavaScript,在服务器端就能实现 shadow DOM 的功能。以下是一个声明式 Shadow DOM 的示例:BxA28资讯网——每日最新资讯28at.com

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

从中可以清晰地看到,我们的文字成功插入到了 slot 标签之中。利用声明式 Shadow DOM,我们能够对之前的示例进行改写:BxA28资讯网——每日最新资讯28at.com

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,代码依然能够正常运行!BxA28资讯网——每日最新资讯28at.com

声明式 Shadow DOM 是一个相对较新的特性,您可以在这篇文档[3]中获取更多详细信息。BxA28资讯网——每日最新资讯28at.com

react 实现流式渲染

现在让我们转换视角,来看看 React 框架中的流式渲染。自 React 18 版本之后,在框架层面上开始支持流式渲染。下面是使用 nextjs 对之前的示例进行改写的代码:BxA28资讯网——每日最新资讯28at.com

import { Suspense } from 'eact'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 代码。BxA28资讯网——每日最新资讯28at.com

关于 React 的流式渲染,您可以在官方的技术层面[4]解释中获取更深入的信息。在本文中,仅作为对流式渲染的概要介绍,不对其进行更为细致的讲解。BxA28资讯网——每日最新资讯28at.com

总结

本文从理论层面深入探讨了流式渲染的相关实现方案。理论上,流式渲染的概念和实现相对简单。HTTP 标准和 Node.js 早在很久以前就对这一特性提供了支持。然而,在实际的工程应用中,流式渲染并非易事。以 React 为例,要实现流式渲染,不仅需要 React 自身作为用户界面(UI)框架提供支持,还需要借助像 nextjs 这样的元框架(meta framework)来赋予服务端相应的能力。BxA28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-96975-0.html我们一起聊聊如何通过流式渲染提升用户体验?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 面试官:Transient关键字修饰的变量当真不可序列化?

下一篇: 纯 CSS 检测滚动的速度和方向

标签:
  • 热门焦点
  • Redmi Pad评测:红米充满野心的一次尝试

    从Note系列到K系列,从蓝牙耳机到笔记本电脑,红米不知不觉之间也已经形成了自己颇有竞争力的产品体系,在中端和次旗舰市场上甚至要比小米新机的表现来得更好,正所谓“大丈夫生居
  • 微信语音大揭秘:为什么禁止转发?

    大家好,我是你们的小米。今天,我要和大家聊一个有趣的话题:为什么微信语音不可以转发?这是一个我们经常在日常使用中遇到的问题,也是一个让很多人好奇的问题。让我们一起来揭开这
  • 在线图片编辑器,支持PSD解析、AI抠图等

    自从我上次分享一个人开发仿造稿定设计的图片编辑器到现在,不知不觉已过去一年时间了,期间我经历了裁员失业、面试找工作碰壁,寒冬下一直没有很好地履行计划.....这些就放在日
  • 这款新兴工具平台,让你的电脑效率翻倍

    随着信息技术的发展,我们获取信息的渠道越来越多,但是处理信息的效率却成为一个瓶颈。于是各种工具应运而生,都在争相解决我们的工作效率问题。今天我要给大家介绍一款效率
  • 一文掌握 Golang 模糊测试(Fuzz Testing)

    模糊测试(Fuzz Testing)模糊测试(Fuzz Testing)是通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法。可以用来发现应用程序、操作系统和网络协议等中的漏洞或
  • 重估百度丨“晚熟”的百度云,能等到春天吗?

    &copy;自象限原创作者|程心排版|王喻可2016年7月13日,百度云计算战略发布会在北京举行,宣告着百度智能云的正式启程。彼时的会场座无虚席,甚至排队排到了门外,在场的所有人几乎都
  • 最“俊美”淘宝卖家,靠直播和短视频圈粉,上架秒光,年销3000万

    来源 | 电商在线文|易琬玉编辑|斯问受访店铺:Ringdoll戒之人形图源:微博@御座的黄山、&ldquo;Ringdoll戒之人形&rdquo;淘宝店铺有关外貌的评价,黄山已经听累了。生于1985年的他,哪
  • 信通院:小米、华为等11家应用商店基本完成APP签名及验签工作

    中国信通院表示,目前,小米、华为、OPPO、vivo、360手机助手、百度手机助手、应用宝、豌豆荚和努比亚等9家应用商店,以及抖音和快手2家新型应用分发平
  • Android 14发布:首批适配机型公布

    5月11日消息,谷歌在今天凌晨举行了I/O大会,本次发布会谷歌带来了自家的AI语言模型PaLM 2、谷歌Pixel Fold折叠屏、谷歌Pixel 7a手机,同时发布了Androi
Top