Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Web性能优化:不要与浏览器预加载扫描器对抗

Web性能优化:不要与浏览器预加载扫描器对抗

原创
作者头像
智影Yodonicc
修改于 2022-05-16 16:36:05
修改于 2022-05-16 16:36:05
5.5K20
代码可运行
举报
文章被收录于专栏:智影Yodonicc智影Yodonicc
运行总次数:0
代码可运行

作者:Jeremy Wagner 原文链接:Don't fight the browser preload scanner 译者:Yodonicc 了解什么是浏览器预加载扫描器,它如何帮助提高性能,以及你如何才能不受其影响。

优化页面速度的一个被忽视的方面就是要对浏览器的内部结构有一定的了解。浏览器进行了某些优化,以提高性能,而我们作为开发者却无法做到这一点——但前提是我们不能无意中阻挠这些优化。

需要了解的一个浏览器内部优化是浏览器预加载扫描器。在这篇文章中,我们将谈一谈预加载扫描器是如何工作的,更重要的是,你可以如何避免妨碍它。

什么是预加载扫描器?

每个浏览器都有一个主要的HTML解析器,它对原始标记进行标记,并将其处理为一个对象模型。这一切都在愉快地进行着,直到解析器发现一个阻塞资源时暂停,例如用<link>元素加载的样式表,或用<script>元素加载的脚本,但没有asyncdefer属性。

图1:浏览器的主要HTML解析器如何被阻塞的图示。在这种情况下,解析器遇到了一个外部CSS文件的<link>元素,它阻止了浏览器解析文档的其余部分,甚至是渲染任何文档,直到CSS被下载和解析。

在CSS文件的情况下,解析和渲染都被阻止,以防止出现无样式内容的闪光(FOUC),即在样式被应用到一个页面之前,可以短暂地看到一个无样式的版本。

图2:FOUC的一个模拟例子。左边是没有样式的web.dev的首页。右边是应用了样式的同一页面。如果浏览器在下载和处理样式表的时候没有阻止渲染,那么无样式的状态就会在瞬间发生。

当浏览器遇到没有deferasync属性的<script>元素时,也会阻止对页面的解析和渲染。

从带有type=module属性<script>元素中加载的脚本,默认情况下是延缓的。

这样做的原因是,当主要的HTML解析器还在做它的工作时,浏览器无法确定任何特定的脚本是否会修改DOM。这就是为什么在文档的末尾加载你的JavaScript是一种常见的做法,这样解析和渲染受阻的影响就变得微不足道。

这些都是浏览器应该阻止解析和渲染的很好的理由,但是阻止这两个重要步骤中的任何一个都是可取的,因为它们会耽误其他重要资源的发现而耽误展示。值得庆幸的是,浏览器通过一个叫做预加载扫描器的二级HTML解析器,尽力缓解了这个问题。

图3:描述预加载扫描器如何与主HTML解析器并行工作以推测性地加载资源的图。在这里,主HTML解析器在开始处理<body>元素中的图像标记之前,由于加载和处理CSS而受阻,但预加载扫描器可以在原始标记中向前看,找到图像资源,并在主HTML解析器解除封锁之前开始加载。

预加载扫描器的作用是推测性的,也就是说,它检查原始标记,以便在主要的HTML解析器发现资源之前,寻找机会获取这些资源。

如何判断预加载扫描器是否在工作?

预加载扫描器的存在是因为渲染和解析受阻。如果这两个性能问题不存在,预加载扫描器就不会很有用。要弄清楚一个网页是否从预加载扫描器中受益,关键取决于这些阻塞现象,为了做到这一点,我们可以为请求引入一个人为的延迟,以找出预加载扫描器的工作位置。

让我们来看看一个带有样式表的基本文本和图片的页面。因为CSS文件同时阻止了渲染和解析,我们可以通过代理服务为样式表引入两秒的人为延迟。这个延迟使我们更容易在网络瀑布图中看到预加载扫描器的工作情况。

图4:在移动设备上通过模拟3G连接在Chrome上运行的网页WebPageTest 网络瀑布图。尽管样式表在开始加载前通过代理被人为地延迟了两秒,但位于标记有效载荷后面的图像被预加载扫描器发现。

正如你在瀑布图中所看到的,即使在渲染和文档解析受阻的时候,预加载扫描器也能发现<img>元素。如果没有这个优化,浏览器就不能在阻塞期间适时地获取东西,更多的资源请求将是串行的而不是并发的。

有了这个玩具般的例子,让我们来看看一些现实世界中预加载扫描器可能被击败的模式,以及如何解决这些问题。

这些模式并不是一个详尽的列表,只是一些常见的模式。

注入的异步脚本

假设你的<head>中的HTML包含一些内联的JavaScript,像这样。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<script>
  const scriptEl = document.createElement('script');
  scriptEl.src = '/yall.min.js';
​
  document.head.appendChild(scriptEl);
</script>

注入的脚本默认是异步的,所以当这个脚本被注入的时候,它的行为就像被应用了async属性一样。这意味着它将尽快运行,而不会阻塞渲染。听起来很理想,对吗?然而,如果我们假设这个内联<script>是在加载外部CSS文件的<link>元素之后,我们会得到一个次优的结果。

图5:在移动设备上通过模拟3G连接在Chrome上运行的网页的WebPageTest网络瀑布图。该页面包含一个样式表和一个注入的异步脚本。在渲染阻塞阶段,预加载扫描器无法发现该脚本,因为它是在客户端注入的。

我们来分析一下这里发生了什么。

  1. 0秒时,主文件被请求。
  2. 在1.4秒时,导航请求的第一个字节到达。
  3. 在2.0秒时,CSS和图片被请求。
  4. 由于解析器在加载样式表时受阻,而注入async脚本的内联JavaScript在2.6秒时出现在样式表之后,因此该脚本提供的功能并不能尽快使用。

这是不理想的,因为对脚本的请求只发生在样式表下载完成之后。This delays the script from running as soon as possible. 这有可能会影响页面的交互时间(TTI, Time to Interactive )。相比之下,由于<img>元素在服务器提供的标记中是可以被发现的,它可以被预加载扫描仪发现。

那么,如果我们使用一个带有async属性的普通<script>标签,而不是将脚本注入DOM,会发生什么?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<script src="/yall.min.js" async></script>

这就是结果。

图6:在移动设备上通过模拟3G连接在Chrome上运行的网页的WebPageTest网络瀑布图。该页面包含一个样式表和一个异步脚本元素。预加载扫描器在渲染阻塞阶段发现了该脚本,并与CSS同时加载。

可能有一些人认为,这些问题可以通过使用 rel=preload来解决。这当然可行,但它可能会带来一些副作用。毕竟,为什么要用rel=preload来解决一个可以通过不向DOM中注入<script>元素来避免的问题呢?

图7:WebPageTest网络瀑布图,该网页在移动设备上的Chrome浏览器上通过模拟的3G连接运行。该页面包含一个样式表和一个注入的异步脚本,但异步脚本被预加载,以确保它更早被发现。

预加载 "解决 "了这里的问题,但它引入了一个新的问题:前两个演示中的异步脚本——尽管被加载在<head>中——是以 "低 "优先级加载的,而样式表则以 "最高 "优先级加载。在最后一个预装异步脚本的演示中,样式表仍然以 "最高 "优先级加载,但脚本的优先级已经提升到 "高"。

资源优先级可以在现代浏览器的网络标签中发现。特别是对于Chrome DevTools,你可以右键点击列标题,以确保优先级列是可见的。请确保在多个浏览器中进行测试,因为资源优先级因浏览器和其他因素而异。

当一个资源的优先级被提高时,浏览器会分配更多的带宽给它。这意味着——即使样式表有最高的优先级——脚本的优先级提高可能会导致带宽争用。这可能是慢速连接的一个因素,或者在资源相当大的情况下。

这里的答案很简单:如果在启动过程中需要脚本,不要通过把它注入DOM来破坏预加载扫描器。根据需要试验一下<script>元素的位置,以及诸如deferasync等属性。

Ilya Grigorik写了一篇内容丰富的文章,对注入的异步脚本进行了详细介绍。如果你想深入了解这个话题,请阅读它。

懒加载的JavaScript

懒加载是一种保存数据的好方法,这种方法经常被应用于图片。然而,有时懒加载被错误地应用于 "折叠上方 "的图片,可以这么说。

这就在预加载扫描器方面引入了潜在的资源可发现性问题,并且会不必要地延迟发现图片的引用、下载、解码和展示所需的时间。让我们以这个图像标记为例。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<img data-src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

使用data-前缀是由JavaScript驱动的懒加载器的一个常见模式。当图片被滚动到视口中时,懒惰加载器会去掉data-前缀,也就是说,在前面的例子中,data-src变成了src。这种更新会提示浏览器获取资源。

这种模式并没有什么问题,直到它被应用于启动时在视口中的图像。因为预加载扫描器并没有像读取src(或srcset)属性那样读取data-src属性,所以图像引用没有被提前发现。更糟糕的是,图像被延迟加载,直到懒惰加载器的JavaScript下载、编译和执行之后。

图8:在移动设备上通过模拟3G连接在Chrome上运行的网页的WebPageTest网络瀑布图。尽管图像资源在启动时在视口中是可见的,但它被不必要地偷懒加载。这破坏了预加载的扫描器,导致了不必要的延迟。

根据图像的大小——这可能取决于视口的大小——它可能是最大内容绘画(LCP, Largest Contentful Paint)的一个候选元素。当预加载扫描器不能提前获取图像资源时,可能是在页面的样式表阻止渲染时,LCP就会受到影响。

重要的是 关于优化LCP的更多信息,超出了本文的范围,请阅读优化最大内容的绘画

解决办法是改变图像标记。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<img src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

这是在启动期间处于视口中的图像的最佳模式,因为预加载扫描器会更快地发现和获取图像资源。

图9:在移动设备上通过模拟3G连接在Chrome上运行的网页的WebPageTest网络瀑布图。预加载扫描器在开始加载CSS和JavaScript之前就发现了图像资源,这让浏览器在加载图像时有了先机。

在这个简化的例子中,结果是在慢速连接的情况下,LCP提高了100毫秒。这可能看起来不是一个巨大的改进,但当你考虑到这个解决方案是一个快速的标记修复,而且大多数网页比这组例子更复杂时,它就是一个巨大的改进。这意味着LCP候选人可能要与许多其他资源争夺带宽,所以像这样的优化变得越来越重要。

重要性 图片并不是唯一可能受到次优懒惰加载模式影响的资源类型。<iframe>元素也会受到影响,由于<iframe>元素可以加载许多子资源,对性能的影响可能会大大恶化。

CSS背景图片

记住,浏览器的预加载扫描器会扫描标记。它并不扫描其他资源类型,比如CSS,它可能涉及对 background-image 属性.所引用的图像的检索。

像HTML一样,浏览器将CSS处理成它自己的对象模型,称为 CSSOM。如果在构建CSSOM时发现了外部资源,这些资源在发现时被请求,而不是由预加载扫描器来处理。

假设你的页面的LCP候选是一个具有CSS background-image属性的元素。以下是资源加载时发生的情况。

图10:在移动设备上通过模拟3G连接在Chrome浏览器上运行的一个网页的WebPageTest网络瀑布图。该页面的LCP候选者是一个具有CSSbackground-image属性的元素(第3行)。它所请求的图像在CSS解析器找到它之前不会开始获取。

在这种情况下,预加载扫描器并没有被击败,而是没有参与。即便如此,如果页面上的LCP候选者是来自一个background-image的CSS属性,你将会想要预加载该图像。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!-- Make sure this is in the <head> below any
     stylesheets, so as not to block them from loading -->
<link rel="preload" as="image" href="lcp-image.jpg">

注意事项 如果你的LCP候选人来自一个background-image的CSS属性,但该图像根据视口大小而变化,你就需要在<link>元素上指定 imagesrcset 属性

这个rel=preload的提示很小,但它可以帮助浏览器比其他方式更早地发现图像。

图11:WebPageTest网络瀑布图,该网页在移动设备上通过模拟的3G连接在Chrome上运行。页面的 LCP 候选是具有 CSSbackground-image属性的元素(第 3 行)。提示帮助浏览器rel=preload比没有提示时快 250 毫秒左右发现图像。

有了这个rel=preload提示,LCP 候选会更快被发现,从而降低 LCP 时间。虽然该提示有助于解决此问题,但更好的选择可能是评估您的图像 LCP 候选是否必须从 CSS 加载。使用<img>标签,您可以更好地控制加载适合视口的图像,同时允许预加载扫描器发现它。

使用客户端 JavaScript 渲染标记

毫无疑问:JavaScript 肯定会影响页面速度。我们不仅依靠它来提供交互性,而且我们还倾向于依靠它来提供内容本身。这在某些方面会带来更好的开发者体验;但开发人员的利益并不总是转化为用户的利益。

可以无效化预加载扫描器的一种模式是使用客户端 JavaScript 呈现标记:

图12:通过模拟 3G 连接在移动设备上的 Chrome 上运行的客户端呈现网页的 WebPageTest 网络瀑布图。因为内容包含在 JavaScript 中并且依赖于框架来呈现,所以客户端呈现的标记中的图像资源对预加载扫描器是隐藏的。等效的服务器渲染体验如图 9 所示

当标记的有效载荷包含在浏览器中并完全由JavaScript渲染时,该标记中的任何资源对预加载扫描器来说都是不可见的。这就延迟了重要资源的发现,这当然会影响到LCP。在这些例子中,与不需要JavaScript的服务器渲染体验相比,对LCP图片的请求被大大延迟了。

这有点偏离了本文的重点,但在客户端渲染标记的影响远远超出了对预加载扫描器的破坏。首先,引入JavaScript来驱动一个不需要的体验,会引入不必要的处理时间,从而影响到 "下一步绘画" Next Paint (INP) 的交互影响。

此外,与服务器发送相同数量的标记相比,在客户端呈现大量标记更有可能生成较长的任务。这样做的原因——除了 JavaScript 涉及的额外处理——是浏览器从服务器流式传输标记并以避免长时间任务的方式进行渲染。另一方面,客户端呈现的标记作为单一的整体任务处理,这可能会影响页面响应性指标,例如除 INP 之外的总阻塞时间 (TBT)首次输入延迟 (FID) 。

这种情况的补救措施取决于对这个问题的回答:是否有理由说明为什么您的页面标记不能由服务器提供而不是在客户端呈现?如果对此的回答是“否”,则应尽可能考虑服务器端渲染 (SSR) 或静态生成的标记,因为这将有助于预加载扫描器提前发现并有机会获取重要资源。

如果您的页面确实需要 JavaScript 来将功能附加到页面标记的某些部分,您仍然可以使用 SSR,或者使用 vanilla JavaScript,或者使用hydration,以获得两全其美的效果。

帮助预加载扫描器帮助你

预加载扫描器是一个非常有效的浏览器优化,可以帮助页面在启动时更快地加载。通过避免破坏其提前发现重要资源的能力的模式,你不仅使自己的开发更简单,你还创造了更好的用户体验,这将在许多指标上带来更好的结果,包括一些网页关键指标

回顾一下,以下是你想从这篇文章中得到的东西。

  • 浏览器预加载扫描器是一个辅助的HTML分析器,如果它被阻挡了,就会在主扫描器之前进行扫描,以伺机发现可以更早获取的资源。
  • 预加载扫描器无法发现服务器在初始导航请求中提供的标记中不存在的资源。打败预加载扫描器的方法可能包括(但不限于)。
    • 用JavaScript将资源注入DOM,无论是脚本、图像、样式表,还是其他任何东西,最好是在服务器的初始标记有效载荷中。
    • 使用JavaScript解决方案,懒、加载折页上方的图像或iframe。
    • 在客户端渲染可能包含引用文档子资源的标记,使用JavaScript。
  • 预加载扫描仪只扫描HTML。它不会检查其他资源的内容——特别是CSS——可能包括对重要资产的引用,包括LCP候选。

如果出于某种原因,你无法避免对预加载扫描器加快加载性能的能力产生负面影响的模式,可以考虑rel=preload资源提示。如果你确实使用了rel=preload,在实验室工具中进行测试,以确保它给你带来预期的效果。最后,不要预装太多的资源,因为当你优先考虑所有的东西时,没有什么会是。

资源

图片来源:来自Unsplash,作者Mohammad Rahmani

注:特别感谢技术指导dazhao(赵达)对本文翻译的审阅指正

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
2 条评论
热度
最新
script标签老早就实现了,美滋滋
script标签老早就实现了,美滋滋
回复回复1举报
请问大佬,文档前面说会阻塞HTML解析器,是阻塞DOM树构建,还是说阻塞渲染。
请问大佬,文档前面说会阻塞HTML解析器,是阻塞DOM树构建,还是说阻塞渲染。
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
浏览器页面渲染全解析过程优化及实战指南详解
将HTML、CSS和JavaScript转换为屏幕上的像素,实现用户可交互的视觉界面。
小焱
2025/05/22
2030
浏览器页面渲染全解析过程优化及实战指南详解
浏览器之资源获取优先级(fetchpriority)
最近,公司在做技术改造升级,老旧项目优化。因为是B端项目居多,所以优化方向也是基于浏览器端的项目改造和处理。
前端柒八九
2023/08/10
1.2K0
浏览器之资源获取优先级(fetchpriority)
浏览器加载解析渲染机制的全面解析
(注1:如果有问题欢迎留言探讨,一起学习!转载请注明出处,喜欢可以点个赞哦!) (注2:更多内容请查看我的目录。)
love丁酥酥
2018/08/27
1.2K0
浏览器加载解析渲染机制的全面解析
穷追猛打,阿里二面问了我30分钟从URL输入到渲染...
同样的问题,可以拿来招聘P5也可以是P7,只是深度不同。所以我重新整理了一遍整个流程,本文较长,建议先收藏。
用户9899350
2022/07/29
6270
穷追猛打,阿里二面问了我30分钟从URL输入到渲染...
web性能优化的15条实用技巧
1.访问DOM会影响浏览器性能,修改DOM则更耗费性能,因为他会导致浏览器重新计算页面的几何变化。<通常的做法是减少访问DOM的次数,把运算尽量留在JS这一端。
徐小夕
2019/10/08
7330
窥探现代浏览器架构(三)
本文是笔者对Mario Kosaka写的inside look at modern web browser系列文章的翻译。这里的翻译不是指直译,而是结合个人的理解将作者想表达的意思表达出来,而且会尽量补充一些相关的内容来帮助大家更好地理解。
进击的大葱
2022/08/22
5550
窥探现代浏览器架构(三)
Web性能优化_知识点精讲
今天,我们继续「前端面试」的知识点。我们来谈谈关于「Web性能优化」的相关知识点。
前端柒八九
2022/12/19
1.4K0
Web性能优化_知识点精讲
Web 性能优化:Preload,Prefetch的使用及在 Chrome 中的优先级
今天,我们将深入研究Chrome 的网络栈,以明确 web 加载原语(如<link rel= preload > & <link rel= prefetch >) 背后的工作原理,以便你能够更有效地使用它们。
前端小智@大迁世界
2019/04/18
2.3K0
Web 性能优化:Preload,Prefetch的使用及在 Chrome 中的优先级
[浏览器]浏览器是怎么渲染页面的?
前端这个岗位的出现最根本的原因是互联网的出现,浏览器是最早互联网的唯一入口。人们通过浏览器浏览各种不同网站的内容。这些内容来自服务器中,但浏览器从服务器拿到这些内容之后,应该怎么展示给用户,这就是前端的职责。所以,最早的时候前端工作者本质上做的是告诉浏览器怎么展示数据。
玖柒的小窝
2021/11/07
5670
[浏览器]浏览器是怎么渲染页面的?
前端-CSS与网络性能
在博客上,CSS 相关的文章却不多。那就结合 CSS 与性能这两大主题,为大家带来一篇文章吧。
grain先森
2019/03/29
1K0
前端-CSS与网络性能
浏览器之性能指标-LCP
前几天,我们写了关于Chrome的FCP,看后台数据,反响还是不错的。那么,今天我们继续讲另外一个比较重要的性能指标LCP。
前端柒八九
2023/08/10
2K0
浏览器之性能指标-LCP
浏览器原理0. 前言1. 解析过程2. 渲染树2.1 CSS样式计算2.2 构建渲染树3. 布局(重要)4. 重绘与重排(重要)5. paint(绘制)6. composite(重要)7. 浏览器加载
身为前端,打交道最多的就是浏览器和node了,也是我们必须熟悉的。接下来我们讲一下浏览器工作原理和工作过程。从url到页面的过程,......,我们直接来到收到服务器返回内容部分开始。
lhyt
2018/10/31
5.4K0
“非主流”的纯前端性能优化
性能优化一直是前端研究的主要课题之一,因为不仅直接影响用户体验,对于商业性公司,网页性能的优劣更关乎流量变现效率的高低。例如 DoubleClick by Google 发现:
2020labs小助手
2020/09/23
5980
现代浏览器探秘(part3):渲染 [每日前端夜话(0x12)]
这是关于浏览器内部工作原理系列的第3部分。 之前,我们介绍了多进程架构和导航流程。 在这篇文章中,我们将看看渲染器进程内部发生了什么。
疯狂的技术宅
2019/03/27
1.5K0
现代浏览器探秘(part3):渲染 [每日前端夜话(0x12)]
浏览器层面优化前端性能(2):Reader引擎线程与模块分析优化点
renderer与DOM元素是相对应的,但并不是一一对应,有些DOM元素没有对应的renderer,而有些DOM元素却对应了好几个renderer,对应多个renderer的情况是普遍存在的,就是为了解决一个renderer描述不清楚如何显示出来的问题,譬如有下拉列表的select元素,我们就需要三个renderer:一个用于显示区域,一个用于下拉列表框,还有一个用于按钮。
周陆军博客
2023/04/09
1.3K0
浏览器渲染(线程视角1)
上一篇 浏览器渲染(进程视角)文章从浏览器的进程模型演进分析了打开一个页面的渲染进程数量,及每个渲染页面的连接,上下文组等内容,那么对于渲染进程内所作的事情怎样的呢?
醉酒鞭名马
2020/05/23
2.4K3
浏览器渲染(线程视角1)
前端不止:Web性能优化 - 关键渲染路径以及优化策略
我问你:“当你从搜索引擎的结果页面选择打开一条搜索结果时,你觉得多长时间之后,如果页面还处于白屏或者没有加载到关键信息,你会选择关掉这个窗口?”
ThoughtWorks
2018/07/23
1.1K0
前端不止:Web性能优化 - 关键渲染路径以及优化策略
CSS和网络性能
CSS对于呈现页面至关重要 - 在找到,下载和解析所有CSS之前,浏览器不会开始呈现 - 因此我们必须尽可能快地将其加载到用户的设备上。 关键路径上的任何延迟都会影响我们的“开始渲染”并让用户看到空白屏幕。
frontoldman
2019/09/03
1.4K0
CSS和网络性能
从 8 道面试题看浏览器渲染过程与性能优化
移动互联网时代,用户对于网页的打开速度要求越来越高。百度用户体验部研究表明,页面放弃率和页面的打开时间关系如下图 所示。
null仔
2020/03/02
1.2K0
阶段五:浏览器中的页面
21 | Chrome开发者工具:利用网络面板做性能分析 页面是浏览器的核心,浏览器中的所有功能都是服务于页面的,Chrome开发者工具又是调试页面的核心工具。 网络面板 控制器 开始或停止抓包 全局搜索 禁止从cache中加载资源 模拟网络 过滤器 抓图信息:Capture screenshots 详细列表:重点内容 下载信息概要 DOMContentLoaded:页面已经构建好DOM,所需要的HTML、CSS和JS文件都已经下载完成 Load:浏览器已经加载了所有的资源(图片、样式表等) 详
六个周
2022/10/28
9290
推荐阅读
相关推荐
浏览器页面渲染全解析过程优化及实战指南详解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验