设为首页 | 收藏本站欢迎来到卓越网络免费免备案CDN加速,DDoS和CC攻击防御,高防CDN管理平台!

已阅读

免费cdn加速提高浏览器性能

作者:cdnfine      来源:cdnfine      发布时间:2019-07-06

我们最近将Universe.com主页的性能提高了十倍以上。 让我们探索一下我们用来实现这个结果的技术。

但首先,让我们找出为什么网站性能很重要(博客文章末尾的案例研究链接):

  • 用户体验 :性能不佳导致无响应,从UI和UX的角度来看,这可能会让用户感到沮丧。

  • 转化和收入 :通常网站速度缓慢会导致客户流失,并对转化率和收入产生负面影响。

  • 搜索引擎优化 :从2019年7月1日开始,谷歌将默认为所有新网站启用移动优先索引。 如果网站在移动设备上运行缓慢,并且没有适合移动设备的内容,那么它们的排名将会降低。

在这篇博文中,我们将简要介绍这些主要领域,这些领域有助于我们提高页面性能:

  • 绩效衡量 : 实验室和现场仪器。

  • 渲染 :客户端和服务器端渲染,预渲染和混合渲染方法。

  • 网络 :CDN,缓存,GraphQL缓存,编码,HTTP / 2和服务器推送。

  • 浏览器中的JavaScript :包大小预算,代码拆分, async和defer脚本,图像优化(WebP,延迟加载,渐进)和资源提示( preload , prefetch , preconnect )。

在某些情况下,我们的主页是使用React(TypeScript),Phoenix(Elixir),Puppeteer(无头Chrome)和GraphQL API (Ruby on Rails) 构建的 。 这就是它在移动设备上的样子:

免费cdn加速提高浏览器性能

宇宙主页和探索

 

 

绩效衡量

 

没有数据,你只是另一个有意见的人。 - W. Edwards Deming

 

 

实验室仪器

 

实验室仪器允许使用预定义的设备和网络设置在受控环境中收集数据。 使用这些仪器,调试任何性能问题并具有良好可重复的测试要简单得多。

Lighthouse是在本地计算机上审核Chrome网页的绝佳工具。 它还提供了一些有关如何提高性能,可访问性,搜索引擎优化等的有用提示。以下是一些使用模拟快速3G和4倍CPU减速的Lighthouse性能审计报告:

免费cdn加速提高浏览器性能

之前和之后:First Contentful Paint (FCP)改进10倍

然而,仅使用实验室仪器存在缺点:它们不一定捕获可能取决于最终用户的设备,网络,位置和许多其他因素的现实瓶颈。 这就是使用现场仪器也很重要的原因。

 

现场仪器

 

现场仪器允许模拟和测量真实的用户页面负载。 有多种服务可以帮助从实际设备获取真实的性能数据:

  • WebPageTest - 允许在不同位置的实际设备上执行来自不同浏览器的测试。

  • 测试我的网站 - 使用基于Chrome使用情况统计信息的Chrome用户体验报告( CrUX ); 它是公开的,每月更新一次。

  • PageSpeed Insights - 结合了实验室(灯塔)和现场(CrUX)数据。

免费cdn加速提高浏览器性能

WebPageTest报告

 

 

 

渲染

 

 

渲染内容有多种方法,每种方法都有其优点和缺点:

  • 服务器端呈现 (SSR)是在服务器端为浏览器获取最终HTML文档的过程。 优点 :搜索引擎可以抓取网站而不执行JavaScript(SEO),快速初始页面加载,代码仅存在于服务器端。 缺点 :非富网站交互,整页重新加载,浏览器功能受限。

  • 客户端呈现是使用JavaScript在浏览器中呈现内容的过程。 优点 :丰富的网站交互,在初始加载后快速呈现路由更改,访问现代浏览器功能(例如,与服务工作者的离线支持)。 缺点 :不是SEO友好,初始页面加载缓慢,通常需要在服务器端实现单页面应用程序(SPA)和API。

  • 预呈现类似于服务器端呈现,但是在构建期间提前而不是运行时发生。优点 :服务构建的静态文件通常比运行服务器,SEO友好,快速初始页面加载更简单。 缺点 :要求在任何代码更改,完整页面重新加载,非富网站交互,有限访问浏览器功能之前预先呈现所有可能的页面。

 

 

客户端呈现

 

 

以前,我们将我们的主页与Ember.js框架一起实现为具有客户端渲染的SPA。我们遇到的一个问题是我们的Ember.js应用程序的大包大小。 这意味着当浏览器下载JavaScript文件,解析,编译和执行时,用户只看到一个空白屏幕:

免费cdn加速提高浏览器性能

死亡的白色屏幕

我们决定使用React重建应用程序的某些部分。

  • 我们的开发人员已经熟悉构建React应用程序(例如嵌入式小部件 )。

  • 我们已经有一些React组件库可以在多个项目中共享。

  • 新页面具有一些交互式UI元素。

  • 有一个庞大的React生态系统,有很多工具。

  • 使用浏览器中的JavaScript,可以构建具有许多不错功能的Progressive Web App 。

 

 

预呈现和服务器端呈现

 

 

例如,使用React Router DOM构建的客户端呈现应用程序的问题仍然与Ember.js相同。JavaScript很昂贵,在浏览器中看到First Contentful Paint需要一段时间。

一旦我们决定使用React,我们就开始尝试其他潜在的渲染选项,以允许浏览器更快地渲染内容。

免费cdn加速提高浏览器性能

使用React的常规渲染选项

  • Gatsby.js允许使用React和GraphQL预呈现页面。Gatsby.js是一个很好的工具,可以支持许多开箱即用的性能优化。 但是,使用预呈现对我们不起作用,因为我们可能有无限数量的页面包含用户生成的内容。

  • Next.js是一个流行的Node.js框架,它允许使用React进行服务器端渲染。但是,Next.js非常自以为是,需要使用其路由器,CSS解决方案等。 我们现有的组件库是为浏览器构建的,与Node.js不兼容。

这就是为什么我们决定尝试一些混合方法 ,尝试从每个渲染选项中获得最佳效果。

 

 

运行时预渲染

 

 

Puppeteer是一个Node.js库,允许使用无头Chrome。 我们想让Puppeteer尝试在运行时进行预渲染。 这使得可以使用一种有趣的混合方法:使用Puppeteer进行服务器端渲染,使用水合作用进行客户端渲染。 以下是Google提供的有关如何使用无头浏览器进行服务器端呈现的一些有用提示。

免费cdn加速提高浏览器性能

Puppeteer用于运行时预呈现React应用程序

使用这种方法有一些优点:

  • 允许SSR,这对SEO有好处。 爬虫不需要执行JavaScript就能看到内容。

  • 允许构建一个简单的浏览器React应用程序一次,并在服务器端和浏览器中使用它。 更快地使浏览器应用程序更快,使SSR更快,更双赢。

  • 在服务器上使用Puppeteer渲染页面通常比最终用户的移动设备更快(连接更好,硬件更好)。

  • Hydration 可以构建丰富的SPA,并可以访问JavaScript浏览器功能。

  • 我们不需要预先了解所有可能的页面以便预先渲染它们。

但是,我们遇到了这种方法的一些挑战:

  • 吞吐量是主要问题。 在单独的无头浏览器进程中执行每个请求会占用大量资源。 可以使用单个无头浏览器进程并在单独的选项卡中运行多个请求。 但是,使用多个选项卡会降低整个过程的性能。

免费cdn加速提高浏览器性能

使用Puppeteer进行服务器端渲染的体系结构

  • 稳定性 。 扩展或缩小许多无头浏览器,保持流程“温暖”并平衡工作负载是一项挑战。 我们尝试了不同的托管方法:从Kubernetes集群中自托管到使用AWS Lambda和Google Cloud Functions的无服务器。 我们注意到后者与Puppeteer有一些性能问题 :

免费cdn加速提高浏览器性能

AWS Lambdas和GCP函数的Puppeteer响应时间

随着我们对Puppeteer越来越熟悉,我们已经迭代了我们的初始方法(如下所示)。 我们还有一些有趣的正在进行的实验,通过无头浏览器渲染PDF。 即使不编写任何代码 ,也可以使用Puppeteer进行自动端到端测试。 除Chrome之外,它现在支持Firefox 。

 

混合渲染方法

 

在运行时使用Puppeteer非常具有挑战性。 这就是我们决定在构建时使用它的原因,它可以在服务器端从运行时返回实际的用户生成内容。 比Puppeteer更稳定,吞吐量更高的东西。

我们决定尝试使用Elixir编程语言。Elixir看起来像Ruby,但运行在BEAM(Erlang VM)之上,它是为了构建容错和稳定的系统而创建的。

Elixir使用Actor并发模型 。 每个“Actor”(Elixir进程)的内存占用量都很小,约为1-2KB。 这允许同时运行数千个孤立的进程。Phoenix是一个Elixir Web框架,它支持高吞吐量,并允许在单独的Elixir进程中处理每个HTTP请求。

我们结合了这些方法,充分利用了每个世界,满足了我们的需求:

免费cdn加速提高浏览器性能

用于预渲染的Puppeteer和用于服务器端渲染的Phoenix

  • Puppeteer在构建期间以我们想要的方式预渲染React页面并将它们保存在HTML文件中(来自PRPL模式的 app shell)。

我们可以继续构建一个简单的浏览器React应用程序,并且无需等待最终用户设备上的JavaScript即可快速初始加载页面。

  • 我们的Phoenix应用程序为这些预渲染页面提供服务,并动态地将实际内容注入HTML。

这使得内容SEO友好,允许按需处理大量各种页面并更容易扩展。

  • 客户端立即接收并开始显示HT ML,然后将React DOM状态保持为常规SPA。

这样,我们就可以构建高度交互的应用程序并可以访问JavaScript浏览器功能。

免费cdn加速提高浏览器性能

使用Puppeteer进行预渲染的体系结构,使用Phoenix进行服务器端渲染,并使用React在客户端进行水合作用

 

 

网络

 

 

 

内容分发网络(CDN)

 

 

使用CDN可以实现内容缓存,并可以加速其在全球的交付。 我们使用Fastly.com ,它服务于超过10%的互联网请求,并被GitHub,Stripe,Airbnb,Twitter等许多公司使用。

快速允许我们使用名为VCL的配置语言编写自定义缓存和路由逻辑。 以下是基本请求流的工作原理,可根据路由,请求标头等自定义每个步骤:

免费cdn加速提高浏览器性能

VCL请求流程

提高性能的另一个选择是使用Fastly在边缘使用WebAssembly(WASM)。可以把它想象成使用无服务器但在边缘使用C,Rust,Go,TypeScript等编程语言.Cloudflare有一个类似的项目来支持WASM on Workers 。

 

 

高速缓存

 

 

尽可能多地缓存请求以提高性能非常重要。 在CDN级别进行缓存可以更快地为新用户提供响应。 通过发送Cache-Control标头进行Cache-Control可以加快浏览器中重复请求的响应时间。

大多数构建工具(如Webpack)允许向文件名添加哈希值。 可以安全地缓存这些文件,因为更改文件将创建新的输出文件名。

免费cdn加速提高浏览器性能

通过HTTP / 2缓存和编码的文件

 

 

GraphQL缓存

 

 

发送GraphQL请求的最常见方法之一是使用POST HTTP方法。 我们使用的一种方法是在Fastly级别缓存一些GraphQL请求:

  • 我们的React应用程序注释了可以缓存的GraphQL查询。

  • 在发送HTTP请求之前,我们通过从请求主体构建哈希来附加URL参数,该请求主体包括GraphQL查询和变量(我们使用Apollo Client自定义fetch )。

  • 默认情况下,Varnish(和Fastly)使用完整的URL作为缓存键的一部分。

  • 这允许我们继续在请求正文中使用GraphQL查询发送POST请求,并在边缘缓存而不会访问我们的服务器。

免费cdn加速提高浏览器性能

使用SHA256 URL参数发送POST GraphQL请求

以下是一些其他潜在的GraphQL缓存策略:

  • 在服务器端缓存:整个GraphQL请求,在解析程序级别上或通过注释模式声明性地。

  • 使用持久化的GraphQL查询并发送GET /graphql/:queryId以便能够依赖HTTP缓存。

  • 通过使用自动化工具(例如Apollo Server 2.0 )或使用GraphQL特定的CDN(例如FastQL )与CDN集成。

 

 

编码

 

 

所有主流浏览器都支持带有Content-Encoding标头的gzip来压缩数据。 这允许向浏览器发送更少的字节,这通常意味着更快的内容传递。 在支持的浏览器中也可以使用更有效的brotli压缩算法。

 

 

HTTP / 2协议

 

 

HTTP / 2是HTTP网络协议的新版本(DevConsole中的h2 )。 由于与HTTP / 1.x相比存在这些差异,切换到HTTP / 2可能会提高性能:

  • HTTP / 2是二进制的,而不是文本的。 解析更高效,更紧凑。

  • HTTP / 2是多路复用的,这意味着HTTP / 2可以通过单个TCP连接并行发送多个请求。 它允许我们不用担心每个主机限制和域分片的浏览器连接。

  • 它使用头压缩 来减少请求/响应大小开销。

  • 允许服务器主动推送响应。 这个功能特别有趣。

 

 

HTTP / 2服务器推送

 

 

有许多编程语言和库不完全支持所有HTTP / 2功能,因为它们为现有工具和生态系统(例如机架 )引入了重大变化。 但即使在这种情况下,仍然可以使用HTTP / 2,至少部分使用。 例如:

  • 在常规HTTP / 1.x服务器前面使用HTTP / 2设置代理服务器,如h2o或nginx 。 例如,Puma和Ruby on Rails可以发送Early Hints ,它可以启用HTTP / 2 Server Push,但有一些限制 。

  • 使用支持HTTP / 2的CDN来提供静态资产。 例如,我们使用这种方法将字体和一些JavaScript文件推送到客户端。

免费cdn加速提高浏览器性能

HTTP / 2推送字体

推出关键的JavaScript和CSS也非常有用。 只是不要过度推动并注意一些问题。

 

 

浏览器中的JavaScript

 

 

 

捆绑尺寸预算

 

 

#1 JavaScript性能规则不是使用JavaScript。 - 我

如果您已有现有的JavaScript应用程序,则设置预算可以提高捆绑包大小的可见性,并使每个人都保持在同一页面上。 超出预算迫使开发人员三思而后行,并尽量减少规模增长。 以下是如何设置预算的一些示例:

  • 根据您的需要或一些推荐值使用数字。 例如, <170KB缩小和压缩JavaScript。

  • 使用当前捆绑包大小作为基准或尝试将其减少,例如,减少10%。

  • 尝试在竞争对手中拥有最快的网站并相应地设置预算。

您可以使用bundlesize包或Webpack性能提示和限制来跟踪预算:

免费cdn加速提高浏览器性能

Webpack性能提示和限制

 

 

杀死你的依赖

 

 

这是Sidekiq作者撰写的热门博客文章的标题。

代码越少,运行得更快。 代码越少bug少。 代码越少占内存越少。 代码越少越容易理解。

不幸的是,JavaScript依赖的现实是你的项目很可能使用了数百个依赖项。试试ls node_modules | wc -l ls node_modules | wc -l 。

在某些情况下,添加依赖项是必要的。 在这种情况下,依赖包大小应该是在多个包之间进行选择时的标准之一。 我强烈推荐使用BundlePhobia :

免费cdn加速提高浏览器性能

BundlePhobia发现将npm包添加到您的包中的成本

 

 

代码分裂

 

 

使用代码分割可能是显着提高JavaScript性能的最佳方法。 它允许拆分代码并仅运送用户当前需要的部分。 以下是代码拆分的一些示例:

  • 路由分别加载在单独的JavaScript块中。

  • 页面上不可立即显示的组件。 例如模态,页脚低于折叠。

  • Polyfills和ponyfill支持所有主流浏览器中的最新浏览器功能。

  • 使用Webpack的SplitChunksPlugin防止代码重复。

  • 根据需要定位文件,以避免一次性运送所有支持的语言。

您可以使用Webpack 动态导入进行代码分割,使用带有 SuspenseReact.lazy 。

免费cdn加速提高浏览器性能

使用动态导入进行代码拆分,使用带有Suspense的React.lazy进行代码拆分

我们构建了一个函数而不是React.lazy来支持命名导出而不是默认导出 。

 

 

异步和延迟脚本

 

 

所有主流浏览器都支持script标记上的async和defer属性:

免费cdn加速提高浏览器性能

加载JavaScript的不同方式

  • 内联脚本对于加载小型关键JavaScript代码非常有用。

  • 当用户或任何其他脚本(例如分析脚本)不需要脚本时,使用带async的脚本对于获取JavaScript而不阻止HTML解析非常有用。

  • 从性能的角度来看,使用带defer脚本可能是获取和执行非关键JavaScript而不阻止HTML解析的最佳方式。 此外,它还可以在调用脚本时保证执行顺序,如果一个脚本依赖另一个脚本,这将非常有用。

以下是head标记中脚本之间的可视化差异:

免费cdn加速提高浏览器性能

脚本获取和执行的不同方式

 

 

图像优化

 

 

虽然与100 KB的图像相比,100 KB的JavaScript具有非常不同的性能成本,但保持图像尽可能轻,这一点非常重要。

减小图像大小的一种方法是在支持的浏览器中使用更轻量级的WebP图像格式。 对于不支持WebP的浏览器,可以使用以下策略之一:

  • 回退到常规JPEG或PNG格式(某些CDN根据浏览器的Accept请求标头自动执行)。

  • 检测到浏览器支持后加载和使用WebP polyfill 。

  • 使用Service Workers监听fetch请求和更改实际URL以使用WebP(如果支持)。

免费cdn加速提高浏览器性能

 

WebP图像

 

仅当视图位于视口中或附近时才懒惰地加载图像是对具有大量图像的初始页面加载最显着的性能改进之一。 您可以在支持的浏览器中使用IntersectionObserver功能,也可以使用一些替代工具来实现相同的结果,例如react-lazyload 。

免费cdn加速提高浏览器性能

滚动期间延迟加载图像

其他一些图像优化可能包括:

  • 降低图像质量以减小尺寸。

  • 调整大小并加载最小的图像。

  • 使用srcset图像属性自动加载高分辨率视网膜显示器的高质量图像。

  • 使用渐进式图像立即显示模糊图像。

免费cdn加速提高浏览器性能

加载常规图像和渐进图像

您可以考虑使用一些通用CDN或专用图像CDN,它们通常实现大多数这些图像优化。

 

资源提示

 

资源提示允许我们优化资源交付,减少往返次数,并获取资源以在用户浏览页面时更快地传递内容。

免费cdn加速提高浏览器性能

带有链接标记的资源提示

  • Preload在当前页面加载的后台下载资源,然后在当前页面上实际使用(高优先级)。

  • Prefetch工作方式类似于preload以获取资源并缓存它们,但用于将来用户的导航(低优先级)。

  • Preconnect允许在HTTP请求实际发送到服务器之前设置早期连接。

免费cdn加速提高浏览器性能

提前预先连接以避免DNS,TCP,TLS往返延迟

还有一些其他资源提示,例如prerenderdns-prefetch 。 可以在响应头中指定其中一些资源提示。 使用资源提示时要小心。 开始制作太多不必要的请求并下载太多数据非常简单,特别是如果用户使用蜂窝连接 。

 

 

结论

 

不断增长的应用程序中的性能是一个无休止的过程,通常需要在整个堆栈中进行不断的更改。

此视频让我想起您想要减少应用包大小。 - 我的同事

免费cdn加速提高浏览器性能

从你现在不需要的飞机上剥离一切! - 珍珠港电影

以下列出了我们使用或计划尝试的其他未提及的潜在性能改进:

  • 使用Service Workers进行缓存,脱机支持和卸载主线程。

  • 内联关键CSS或使用功能CSS来减少长期的大小。

  • 使用字体格式,如WOFF2而不是WOFF(高达50%+压缩)。

  • 使browserslist保持最新。

  • 使用webpack-bundle-analyzer直观地分析构建块。

  • 优选较小的包(例如date-fns )和插件,允许减小大小(例如lodash-webpack-plugin )。

  • 尝试preact , lit-htmlsvelte 。

  • 在CI中运行灯塔 。

  • 使用React 进行水合和流动 。

有许多令人兴奋的想法可供尝试。 我希望这些信息和一些案例研究能够激发您思考应用程序的性能:

据亚马逊计算 , 每年仅1秒的页面加载速度下降可能会花费16亿美元。

沃尔玛每加载1秒钟的转换次数增加了2%。 每100毫秒的改进也使收入增加了1%。

 

 

重建Pinterest页面的性能导致等待时间减少40%,SEO流量增加15%,注册转换率增加15%。

英国广播公司已经看到 ,他们在网站加载所需的每一秒钟内就会失去额外10%的用户。

对新的更快的FT.com的测试表明,用户的参与度提高了30% - 这意味着更多的访问次数和更多的内容被消费。

Instagram通过降低显示评论所需的JSON响应大小,将展示次数和用户个人资料滚动互动增加了33%。

Keywords: 免费CDN加速 免备案CDN加速 高防CDN加速