PRPL模式详解 | PRPL patterns

PRPL模式 🚀 Preload | Render | Pre-cache | Lazy Load

⭐Firstly

推荐一个网站 patterns

设计模式,渲染模式,性能模式……

🔑Intro

什么是PRPL?

PRPL 描述了一种可以提高网页加载速度和交互性的模式

  • Preload:高优先级加载关键资源,加快页面加载速度
  • Render:关键资源下载完后尽快渲染,而不是等待所有资源加载完毕再渲染
  • Pre-cache:首次访问时预缓存资源到本地,以便后续页面直接从缓存读取
  • Lazy load:延迟加载路由和非关键资源

为什么需要PRPL?

  • 当我们想访问一个网站时,我们首先必须向服务器发出请求以获取这些资源。入口点指向的文件从服务器返回,通常是我们应用程序的初始 HTML 文件,浏览器的 HTML 解析器在开始从服务器接收此数据后立即开始解析这些数据。如果解析器发现需要更多资源,例如样式表或脚本,则会向服务器发送另一个 HTTP 请求以获取这些资源
  • 反复请求资源并不是最佳选择,因为我们试图尽量减少客户端和服务器之间的往返次数
  • PRPL 模式的重点是优化初始加载。在初始路由完全加载和呈现之前,不会加载其他资源

HTTP/1.1 vs. HTTP/2

![](https://assets-global.website-files.com/5ff66329429d880392f6cba2/6149cbd7fd4bdd7c82f55cc6_http1 vs http2.png)

  • HTTP/1.1 在请求和响应中使用换行符分隔的纯文本协议,而 HTTP/2 将请求和响应分割成“”。包含标头和正文字段的 HTTP 请求至少分为两个帧:标头帧和数据帧
  • HTTP/1.1 客户端和服务器之间最多有6个TCP连接。通过同一个TCP连接发送新请求之前必须先解决之前的请求,如果一个请求耽误很长时间就会阻止后续请求,这个问题称为“队头阻塞
  • HTTP/2 将消息编码为二进制数据,并建立了双向流,可以实现包含多个双向流的单个TCP。双向流可以在客户端和服务器之间承载多个请求和响应帧,处理好的帧可以及时返回,有效解决了队头阻塞的问题

  • 服务器推送 server push

    • 与传统的HTTP请求-响应模式不同,服务器推送不需要等待客户端的请求,而是由服务器在检测到客户端需要某些资源时主动将这些资源推送给客户端

    • 客户端收到其他资源后,这些资源将存储在浏览器缓存中。当在解析入口文件时发现资源时,浏览器可以快速从缓存中获取资源,而不必向服务器发出 HTTP 请求

    • 由于服务器无法知道客户端是否已经缓存了这些资源,因此即使已经存在于客户端的HTTP缓存中,服务器也可能会继续推送这些资源,导致客户端重复获取相同的资源。

      PRPL模式提出了一种解决方案。它在页面初始加载完成后利用Service Worker来缓存这些额外的资源。这样,即使服务器再次推送相同的资源,客户端也可以通过Service Worker从本地缓存中获取这些资源,而不必再次从服务器请求。这样就避免了不必要的网络请求,提高了页面加载速度和用户体验。

🌙lighthouse

生命周期

Lighthouse 运行测评的过程有一套完整的生命周期,可以划分成三个主要流程:

  • Collecting(收集数据):这一步会调用内置的驱动程序(Driver) ,其作用是通过谷歌开发工具协议( Chrome DevTools Protocol) 调起浏览器,并创建新的 tab 请求待测评的站点,通过浏览器采集站点数据并将结果(称之为 Artifacts)保存在本地临时目录。

  • Auditing(分析数据):这一步读取 Artifacts 数据,根据内置的评判策略逐条进行检查并计算出各项的数字形式得分。

  • Report(生成报告):这个流程将评分结果按照 PWA、性能、无障碍访问、最佳实践等纬度进行划分,以 JSON、HTML 等格式输出。

PWA

渐进式网页应用(ProgressiveWebApp)

PWA 可以在浏览器上访问,也可以单独安装成一个应用在系统上。

当Chrome检测到当前访问的网页支持PWA的时候,在地址栏的右端就会出现一个安装按钮,点击即可将这个PWA变成一个应用安装到浏览器中。

而在Android上,使用Chrome浏览PWA站点时也会有相应的提示,添加到应用之后就会自动进行编译安装。iOS上面使用Safari打开网站然后在菜单中选择添加到Home Screen就可以了,之后点开应用图标就会以独立应用形式出现,而不是通过Safari加载网页。

一些指标

  • 性能

    • 首次内容绘制、可交互时间、速度指标
  • 访问无障碍

    • 相关指标,比如屏幕阅读器友好
  • 最佳实践

    • 比如推荐使用 https,跨域的跳转链接需要使用 rel 标识,不能使用废弃的 API等等
  • 搜索引擎优化

    • 比如图片元素使用 alt 属性等等提高搜索引擎搜索排名,便于搜索引擎能找到你这个网站

可以测试自己的网站,在开发过程中持续监测和改进

以下是上述pattern.dev网页的分析报告:

💡Preload

预加载资源

preload 提供了一种声明式的命令,让浏览器**提前加载指定资源(加载后并不执行)**,在需要执行的时候再执行。提供的好处主要是

  • 将加载和执行分离开,可不阻塞渲染和 document 的 onload 事件
  • 通过提前加载指定资源,可以提高网页的性能和用户体验,尤其是对于关键资源,如字体、CSS 文件、JavaScript 文件等。
  • 加载
    • 加载指的是将 JavaScript 文件从服务器下载到浏览器的过程
  • 执行
    • 执行指的是浏览器解析和执行 JavaScript 代码的过程

使用preload

  • 语法

    1
    <link rel="preload" href="url/to/preload" as="type">
  • as可选属性

关于prefetch

  • prefetch 用于在浏览器空闲时预先请求未来可能需要的资源,以加快后续页面加载速度。它告诉浏览器这些资源可能会在将来的页面中用到,但当前页面并不需要立即使用。

  • 语法

    1
    <link rel="prefetch" href="url/to/preload">

使用场景

  • 字体提前加载

    1
    <link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin />
  • 动态加载,但不执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 预先加载脚本
    let link = document.createElement("link");
    link.href = "myscript.js";
    link.rel = "preload";
    link.as = "script";
    document.head.appendChild(link);

    // 立即执行脚本
    let script = document.createElement("script");
    script.src = "myscript.js";
    document.body.appendChild(script);
  • 基于标记语言的异步加载

    1
    2
    3
    4
    5
    6
    <link
    rel="preload"
    as="script"
    href="async_script.js"
    onload="let script = document.createElement('script'); script.src = this.href; document.body.appendChild(script);"
    />

    这一段话首先创建一个链接,然后设置脚本路径,再加载完成之后把脚本添加到页面中,这样异步操作可以保证

💡Render

如果你的资源影响了你的 First Paint ,lighthouse会给出一个警告:

  • 内联关键 JavaScript 和 CSS

    • 将关键的 JavaScript 和 CSS 直接嵌入到 HTML 页面中,可以减少由于请求这些资源而引起的延迟。这可以通过将 JavaScript 使用 async 属性异步加载,以及将关键 CSS 内联到页面头部来实现。
    • 然而,内联代码会增加 HTML 文件的大小,并且不易维护,因为所有的代码都在一个文件中。此外,内联的资源也无法被浏览器单独缓存,因为它们与页面内容混合在一起。
  • 服务器端渲染(Server-Side Rendering,SSR)

    • 在服务器端生成页面的 HTML,然后将其发送给客户端。这样,在客户端加载 JavaScript 和执行脚本之前,用户就可以立即看到页面内容。
    • 这可以改善页面的首次渲染时间,因为它减少了用户等待的时间。然而,SSR 可能会增加 HTML 文件的大小,导致页面下载时间延长。另外,它也会增加服务器端的负载和复杂性。

💡Pre-cache

  • Service Worker

    • 服务工作线程充当浏览器和网络之间的代理,它可以拦截网络请求,并且可以将资源直接从缓存中获取,而不必每次都从服务器请求资源。
    • 这样可以提高页面加载速度,尤其是在用户重复访问应用程序时。
  • pre-cache

    • 通过在服务工作线程中实现预缓存逻辑,可以将应用程序所需的核心资源提前缓存到本地。这样,在用户首次访问应用程序时,这些资源就已经存在于本地缓存中,可以直接从缓存中获取,而无需等待服务器响应。
    • 这不仅提高了页面加载速度,还使得用户可以在离线状态下访问应用程序。
  • 使用第三方库简化生成Service Worker

    • 为了简化服务工作线程的创建和管理,可以使用第三方库,例如Workbox。

💡Lazy load

如果你的网站加载太多资源,lighthouse会提示你:

  • 为了首次加载更小的JavaScript,其中只包含可以尝试拆分bundle,对于剩下的资源按需要懒加载块

  • 如果你成功的拆分了bundle,给重要的chunk加上preload,浏览器会提高下载的优先级。

⭐Conclusion

PRPL 模式的关键思想是尽可能快地加载应用程序的关键部分,并在后续页面使用中继续提供良好的性能

  1. Preload(预加载):在页面加载期间,服务器可以向客户端推送关键资源,例如 HTML、CSS、JavaScript 等。这些资源可以通过 HTTP/2 的服务器推送功能或其他技术来实现。
  2. Render(渲染):在加载阶段,应用程序应该尽可能快地开始渲染页面内容,以使用户尽快看到有用的信息。这意味着应用程序应该优先加载和渲染视觉上的关键内容,而不是等待所有资源都加载完毕后再进行渲染。
  3. Pre-cache(预缓存):在首次访问应用程序时,可以通过Service Worker将关键资源预先缓存到客户端,以便后续页面使用时可以直接从缓存中获取。
  4. Lazy-load(延迟加载):延迟加载是指在后续页面使用时动态加载额外的资源,而不是在页面初始加载阶段加载所有资源。

📕Reference