加载中

About the author:

Addy Osmani,Eng. Manager at Google working on Chrome • Passionate about making the web fast.

Building interactive sites can involve sending JavaScript to your users. Often, too much of it. Have you been on a mobile page that looked like it had loaded only to tap on a link or tried to scroll and nothing happens?

Byte-for-byte, JavaScript is still the most expensive resource we send to mobile phones, because it can delay interactivity in large ways.


JavaScript processing times for CNN.com as measured by WebPageTest (src). A high-end phone (iPhone 8) processes script in ~4s. Compare to the ~13s an average phone (Moto G4) takes or the ~36s taken by a low-end 2018 phone (Alcatel 1X).

Today we’ll cover some strategies you can use to deliver JavaScript efficiently while still giving users a valuable experience.

tl;dr:

  • To stay fastonly load JavaScript needed for the current page.Prioritize what a user will need and lazy-load the rest with code-splitting. This gives you the best chance at loading and getting interactive fast. Stacks with route-based code-splitting by default are game-changers.

  • Embrace performance budgets and learn to live within them. For mobile, aim for a JS budget of < 170KB minified/compressed. Uncompressed this is still ~0.7MB of code. Budgets are critical to success, however, they can’t magically fix perf in isolation. Team culture, structure and enforcement matter. Building without a budget invites performance regressions and failure.

  • Learn how to audit and trim your JavaScript bundles. There’s a high chance you’re shipping full-libraries when you only need a fraction, polyfills for browsers that don’t need them, or duplicate code.

  • Every interaction is the start of a new ‘Time-to-Interactive’; consider optimizations in this context. Transmission size is critical for low-end mobile networks and JavaScript parse time for CPU-bound devices.

  • If client-side JavaScript isn’t benefiting the user-experience, ask yourself if it’s really necessary. Maybe server-side-rendered HTML would actually be faster. Consider limiting the use of client-side frameworks to pages that absolutely require them. Server-rendering andclient-rendering are a disaster if done poorly.

(Video for my recent talk on “The Cost of JavaScript” on which this write-up is based :https://youtu.be/63I-mEuSvGA

关于作者: Addy Osmani, 英国。谷歌的经理,在 Chrome • Passionate 负责改善网页速度。

建立交互式网站包括向用户发送 JavaScript 。通常,太多了。你是否经历过在一个手机页面上,它看起来已经加载好了,但是点击一个链接或者试图滚动页面的时候,什么也没发生?

一字节又一字节,JavaScript 仍然是我们发送给手机的代价最大的资源,因为它会很大程度上延迟交互。

由 WebPageTest(src) 评测的 CNN.com 的 JavaScript 处理时间。高端手机(iPhone8)在约4s的时间处理脚本。相比较而言,普通手机(Moto G4)是约13s的时间,以及2018年低端手机(Alcatel 1X)是约36s。

现在我们讨论一些策略,可以让你高效地传送 JavaScript ,同时给用户提供一个有价值的体验。

概括:

  • 要保持快速,则只加载当前页面必要的 JavaScript 。优先考虑用户需要的内容,然后使用代码拆分延迟加载剩下来的内容。这是快速加载和交互的最好的机会。默认情况下,基于路由的代码拆分堆栈是一个转折。

  • 接受性能预算,学会在预算中生活。对于手机来说,JS的预算目标为简化/压缩后小于170KB。未压缩时代码约为0.7MB。预算对成功至关重要,然而,他们单独不能神奇地修正 perf 数值。团队文化,结构和强制措施。没有预算的项目建立会导致性能退化并导致失败。

  • 学习如何审计并裁剪 JavaScript 捆绑库。当你只需要一小部分却搭载了整个库,浏览器不需要的填充字符,或者重复代码,这些很容易发生。

  • 每个交互都是一个新的“交互时间”的开始;考虑在这种情况下进行优化。传送数据的大小对低端手机网络至关重要,而且 JavaScript 解析时间受设备 CPU 限制。

  • 如果客户端 JavaScript 对用户体验没有好处,问问自己是否真的有必要。也许服务端渲染 HTML 会更快一些。考虑将客户端框架限制到绝对需要它们页面上的使用。如果做的不好,服务器渲染和客户端渲染都会是灾难。

(本文基于我最近的“JavaScript 的代价”的演讲:https://youtu.be/63I-mEuSvGA

The web is bloated by user “experience”

When users access your site you’re probably sending down a lot of files, many of which are scripts. From a web browsers’ perspective this looks a little bit like this:


A mad rush of files being thrown at you.

As much as I love JavaScript, it’s always the most expensive part of your site. I’d like to explain why this can be a major issue.


The median webpage today currently ships about 350 KB of minified and compressed JavaScript. Uncompressed, that bloats up to over 1MB of script a browser needs to process.

Note: Unsure if your JavaScript bundles are delaying how quickly users interact with your site? Check out Lighthouse.


Statistics from the HTTP Archive state of JavaScript report, July 2018 highlight the median webpage ships ~350KB of minified and compressed script. These pages take up to 15s to get interactive.

Experiences that ship down this much JavaScript take more than 14+ seconds to load and get interactive on mobile devices.

A large factor of this is how long it takes to download code on a mobile network and then process it on a mobile CPU.

Let’s look at mobile networks.


Countries that perform better in a particular metric are shaded darker. Countries not included are in grey. It’s also worth noting that rural broadband speeds, even in the US, can be 20% slower than urban areas.

This chart from OpenSignal shows how consistently 4G networks are globally available and the average connection speed users in each country experience. As we can see, many countries still experience lower connection speeds than we may think.

Not only can that 350 KB of script for a median website from earlier take a while to download, the reality is if we look at popular sites, they actually ship down a lot more script than this:


Uncompressed JS bundle size numbers from “Bringing Facebook.com and the web up to speed”. Sites like Google Sheets are highlighted as shipping up to 5.8MB of script (when decompressed).

We’re hitting this ceiling across both desktop and mobile web, where sites are sometimes shipping multiple megabytes-worth of code that a browser then needs to process. The question to ask is, can you afford this much JavaScript?

网站因用户“体验”而膨胀

当用户访问网站,你可能正在下载大量文件,其中很多都是脚本。从给一个web浏览器的角度来看有点像这个:


扔给你一大堆文件

虽然我很喜欢JavaScript,但它总是网站中消耗最大的东西。我想解释一下为什么这是一个主要问题。

现在中等的web页面搭载了大概350KB的简化或压缩后的JavaScript脚本。浏览器需要处理的未压缩的脚本膨胀到了超过1MB。

注:不确定你的JavaScript包是否延迟了用户与网站交互速度?查看Lighthouse

2018年7月的HTTP压缩状态的JavaScript报告中的统计突出显示了中等web页面搭载了约350KB的简化或压缩后的脚本。这些页面要花15s才能交互。

在移动设备上,搭载这么多的JavaScript脚本从经验来看要花费超过14+秒才能加载并交互

其中的一个很大的因素是在移动网络中下载代码,然后再移动设备CPU上处理它,这个过程所花费的时间。

我们来看移动网络。

在某一指标上表现较好的国家,颜色较深。不包括在内的国家是灰色的。还有值得注意的是,即使在美国,农村的宽带速度要比城市慢20%。

这个来自OpenSignal的图表展示了全球4G网络的稳定性,以及每个国家的用户体验到的平均连接速度。正如我们看到的,很多国家的连接速度仍比我们想象中要慢。

不仅中型网站的350KB的脚本要花上一段时间才能下载,事实上,如果我们浏览热门网站,实际上会加载比这更多的脚本:


Facebook.com和其他网址相关数据”中的未压缩的JS包大小数据。像谷歌表格这样的网站被突出显示为最多加载5.8MB的脚本(在解压缩后)。

我们在桌面和移动web上都遇到了这个瓶颈,这些网站有时会加载几兆字节的代码,然后浏览器需要处理这些代码。问题是,你能负担得起这么多JavaScript脚本吗

JavaScript has a cost


“Sites with this much script are simply inaccessible to a broad swath of the world’s users; statistically, users do not (and will not) wait for these experiences to load” — Alex Russell

Note: If you’re sending too much script, consider code-splitting to break up bundles or reducing JS payloads using tree-shaking.

Sites today will often send the following in their JS bundles:

  • A client-side framework or UI library

  • A state management solution (e.g. Redux)

  • Polyfills (often for modern browsers that don’t need them)

  • Full libraries vs. only what they use (e.g. all of lodash, Moment + locales)

  • A suite of UI components (buttons, headers, sidebars etc.)

This code adds up. The more there is, the longer it will take for a page to load.

Loading a web page is like a film strip that has three key moments.

There’s: Is it happening? Is it useful? And, is it usable?


Loading is a journey. We’re shifting to increasing caring about user-centric happiness metrics. Rather than just looking at onload or domContentLoaded, we now ask “when can a user actually *use* the page?”. If they tap on a piece of user-interface, does it respond right away?

Is it happening is the moment you’re able to deliver some content to the screen. (has the navigation started? has the server started responding?)

Is it useful is the moment when you’ve painted text or content that allows the user to derive value from the experience and engage with it.

And then is it usable is the moment when a user can start meaningfully interacting with the experience and have something happen.

I mentioned this term “‘interactive” earlier, but what does that mean?


A visualization of Time-to-Interactive highlighting how a poorly loaded experience makes the user think they can accomplish a goal, when in fact, the page hasn’t finished loading all of the code necessary for this to be true. With thanks to Kevin Schaaf for the interactivity animation

For a page to be interactive, it must be capable of responding quickly to user input. A small JavaScript payload can ensure this happens fast.

Whether a user clicks on a link, or scrolls through a page, they need to see that something is actually happening in response to their actions. An experience that can’t deliver on this will frustrate your users.


Lighthouse measures a range of user-centric performance metrics, like Time-to-Interactive, in a lab setting.

One place this commonly happens is when folks server-side render an experience, and then ship a bunch of JavaScript down afterward to “hydrate” the interface (attaching event handlers and extra behaviors).

When a browser runs many of the events you’re probably going to need, it’s likely going to do it on the same thread that handles user input. This thread is called the main thread.

Loading too much JavaScript into the main thread (via <script>, etc) is the issue. Pulling JS into a Web Worker or caching via a Service Workerdoesn’t have the same negative Time-to-Interactive impact.

(Here’s an example where a user may tap around some UI. Ordinarily, they might check a checkbox or click a link and everything’s going to work perfectly fine. But if we simulate blocking the main thread, nothing’s able to happen. They are not able to check that checkbox or click links because the main thread is blocked:https://youtu.be/N5vFvJUBS28

Avoid blocking the main thread as much as possible. For more, see “Why web developers need to care about interactivity

JavaScript 有代价

“含有这么多脚本的网站根本不能送达全球的诸多用户;统计表示,用户不会(以后也不会)等待它们加载” — Alex Russell

注:如果你使用了大量的脚本,应该考虑使用 code-splitting 对其进行分解,或者使用 tree-shaking 技术减少 JavaScript 的加载量

现代网站通常会通过 JS 包发送下面这些东西:

  • 客户端框架或 UI 库

  • 状态管理(比如 Redux)

  • Polyfills(一般现代浏览器不需要他们)

  • 完整的库或仅用到的部分(比如 lodash 完整库、Moment + 其本地库)

  • 一套 UI 组件(按钮、顶部、侧边栏等)

累积起来的代码越来越多,页面加载的时候也就越来越长。

加载网页就像电影胶片一样,有三个关键时刻。

即:是否发生?是否有用?是否可用?

加载是一个过程。我们正逐渐开始关心用户的良好体验。我们不再盯着 onload 和 domContentLoaded,而是会问“用户什么时候才能正常使用页面?”如果用户点击用户界面中L的o某个地方,是否有所反馈?

是否正在发生是指屏幕上开始显示某些内容。(导航开始了吗?服务器在响应吗?)

是否有用 指文本或内容显现之后,用户是否通过体验或参与感受到价值。

还有是否可用是指用户可以根据经验开始交互并发生一些事情。

我之前也提到过这个术语:“交互”,它到底是什么意思呢?

交互时间的可视化强调,不好的体验会让用户认为他们能达到某个目标,但实际上页面还没有加载完要达到这个目标所需要的代码。感谢 Kevin Schaaf 的关于交互的动画

对于要交互的页面,它必须能够快速响应用户输入。较小的 JavaScript 可以保证快速响应。

无论用户点击链接还是滚动页面,他们都需要看到有反馈他们动画的事情发生。如果做不到这样的体验,用户就会感沮丧。

灯塔有一系列以用户为中心的性能指标,比如在实验设置中的交互时间。

通常发生的地方是当服务端在渲染的过程中,下载一堆“溶入”界面的 JavaScript(添加事件处理函数和其它行为)。

浏览器可能会在处理用户输入的线程上运行许多可能需要处理的事件。这个线程称为主线程。

在主线程上加载太多 JavaScript(通过 <script> 等)会是个问题。把脚本加载到  Web Worker 或者由 Service Worker 处理脚本会减轻这些与交互时间相关的负责影响。

(这里有一个用户点击 UI 的例子。通常,用户勾选复选框,或者点击链接,一切都很美好。但如果我,们模拟阻塞主线程,就什么事都不会发生了。用户无法勾选复选框,也不能点击连接,因为主H线程被阻塞了:https://youtu.be/N5vFvJUBS28

应该尽可能地避免阻塞主线程。了解更多内容,请看 为什么 Web 开发者需要关心交互性

We’re seeing teams we partner with suffer JavaScript impacting interactivity across many types of sites.


JavaScript can delay interactivity for visible elements. Visualized are a number of UI elements from Google Search where

Too much (main thread) JavaScript can delay interactivity for visible elements. This can be a challenge for many companies.

Above are a few examples from Google Search where you could start tapping around the UI, but if a site is shipping too much JavaScript down, there could be a delay before something actually happens. This can leave the user feeling a bit frustrated. Ideally, we want all experiences to get interactive as soon as possible.


Time-to-Interactive of news.google.com as measured by WebPageTest and Lighthouse (source)

Measuring the Time-to-Interactive of Google News on mobile, we observe large variance between a high-end getting interactive in ~7s vs. a low-end device getting interactive in 55s. So, what is a good target for interactivity?


When it comes to Time to Interactive, we feel your baseline should be getting interactive in under five seconds on a slow 3G connection on a median mobile device. “But, my users are all on fast networks and high-end phones!” …are they? You may be on “fast” coffee-shop WiFi but effectively only getting 2G or 3G speeds. Variability matters.

我们看到我们合作的团队遭受JavaScript影响了许多类型网站的交互性。

JavaScript可以延迟可见元素的交互性。可视化是Google搜索中的一些UI元素

太多(主线程)JavaScript可以延迟可见元素的交互性。这对许多公司来说都是一个挑战。

以上是Google搜索中的一些示例,您可以在这些示例中开始使用UI,但如果某个网站运行过多的JavaScript,则可能会在实际发生某些事情之前出现延迟。这会让用户感到有点沮丧。理想情况下,我们希望所有体验尽快互动。

通过WebPageTest和Lighthouse衡量news.google.com的互动时间(来源)

通过衡量Google新闻在移动设备上的交互时间,我们观察到大约7s的高端交互与低端设备在55秒内实现交互的巨大差异。那么,什么是交互性的良好目标?

谈到Time to Interactive,我们认为您的基准应该是在中等移动设备上的慢速3G连接上以五秒钟的速度进行交互。“但是,我的用户都在使用快速网络和高端手机!”......是吗?你可能会使用“快速”的咖啡店WiFi,但实际上只能获得2G或3G的速度。多变性问题

Who has shipped less JavaScript and reduced their Time-to-Interactive?


Let’s design for a more resilient mobile web that doesn’t rely as heavily on large JavaScript payloads.

Interactivity impacts a lot of things. It can be impacted by a person loading your website on a mobile data plan, or coffee shop WiFi, or just them being on the go with intermittent connectivity.


When this happens, and you have a lot of JavaScript that needs to be processed, users can end up waiting for the site to actually render anything. Or, if something does render, they can be waiting a long time before they can interact with anything on the page. Ideally, shipping less JavaScript would alleviate these issues.

谁传输更少的 JavaScript 以减少响应时间?


我们来设计一个更具弹性的 Web,它不依赖于加载巨大的 JavaScript。

交互性会影响很多东西。它可能会影响网站的移动数据规划,或者咖啡厅的 WiFi,或者他们I只是伴随着时断时续的连接。

这些事情发生的时候,你有一大堆的 JavaScript 需要运行,用户可以放弃等待网站的渲染。另外,如果有东西在渲染,也需要等待大量的时间才可以交互。理想情况下,较少的 JavaScript 可以减轻这些问题。

Why is JavaScript so expensive?

To explain how JavaScript can have such a large cost, I’d like to walk you through what happens when you send content to a browser. A user types a URL into the browser’s address bar:


A request is sent to a server which then returns some markup. The browser then parses that markup and discovers the necessary CSS, JavaScript, and images. Then, the browser has to fetch and process all of those resources.

The above scenario is an accurate depiction of what happens in Chrome when it processes everything that you send down (yes, it’s a giant emoji factory).

One of the challenges here is that JavaScript ends up being a bottleneck. Ideally, we want to be able to paint pixels quickly, and then have the page interactive. But if JavaScript is a bottleneck, you can end up just looking at something that you can’t actually interact with.

We want to prevent JavaScript from being a bottleneck to modern experiences.

One thing to keep in mind as an industry is that, if we want to be fast at JavaScript, we have to download it, parse it, compile it, and execute it quickly.


That means we have to be fast at the network transmission and the processing side of things for our scripts.

为什么 JavaScript 如此昂贵?

为了解释 JavaScript 会有如此之大的代价,我想告诉你在内容发送到浏览器之后发生了些什么。当用户在浏览器的地址栏输入 URL:

请求会被发送到服务器,然后服务器会返回一些标记。接着,浏览器解析这些标记,并找到必不的可少的 CSS、JavaScript 和图片。然后,浏览器还得获取并处理所有这些资源。

上面的动画准确描述了 Chrome 在处理你发送的所有内容时要干的事情(确实,它是一个巨大的表情工厂)。

这里存在一个挑战:JavaScript 最终会成为瓶颈。设想,我们希望能快速画出每一个像素,然后让页面可以交互。但是,如果 JavaScript 成为瓶颈,你最终只能看到东西却不能交互。

我们希望防止 JavaScript 为成现代体验的瓶颈。

要记住一点,作为一个流程,如果我们想要 JavaScript 变得更快,我们就必须快速地下载、解析、编译并执行它。

也就是说,我们必须保证快速的网络传输,以及处理关于脚本其它方面的事情。

If you spend a long time parsing and compiling script in a JavaScript engine, that delays how soon a user can interact with your experience.

To provide some data about this, here’s a breakdown of where V8 (Chrome’s JavaScript engine) spends its time while it processes a page containing script:


JavaScript parse/compile = 10–30% of the time spent in V8 (Chrome’s JS engine) during page load

The orange represents all the time spent parsing JavaScript that popular sites are sending down. In yellow, is the time spent compiling. Together, these take anywhere up to 30% of the time it takes to process the JavaScript for your page — this is a real cost.

As of Chrome 66, V8 compiles code on a background thread, reducing compile time by up to 20%. But parse and compile are still very costly and it’s rare to see a large script actually execute in under 50ms, even if compiled off-thread.

Another thing to keep in mind with JavaScript is that all bytes are not equal. A 200 KB script and a 200 KB image have very different costs.


Not all bytes weigh the same. A 200KB script has a very different set of costs to a 200KB JPG outside of the raw network transmission times for both sets of bytes.

They might take the same amount of time to download, but when it comes to processing we’re dealing with very different costs.

A JPEG image needs to be decoded, rasterized, and painted on the screen. A JavaScript bundle needs to be downloaded and then parsed, compiled, executed —and there are a number of other steps that an engine needs to complete. Just be aware that these costs are not quite equivalent.

One of the reasons why they start to add up and matter is mobile.

如果你花很长的时间在 JavaScript 引擎中解析和编译脚本,就是延迟用户与你的体验交互的时间。

为了提供这方面的数据,这里有一个 V8(Chrome 的 JavaScript 引擎)在处理页面中脚本的时间分解数据:

JavaScript 解析/编译 = 在页面加载时 10–30% 时间消耗在 V8 (Chrome 的 JS 引擎) 上

橙色代表了当下流行的网站消耗在解析 JavaScript 上的全部时间。黄色部分则是编译所消耗的时间。它们总计占用了处理页面上 JavaScript 30% 的时间 —— 这是真实的成本。

对于 Chrome66 来说,V8 在后台线程中编译代码,将编译时间减少了 20%。但是解析和编译的代价仍然很高,而且想要看到一个大型脚本执行时间少于 50ms,实属罕见,哪怕不在主线程编译。

另一个要知道的是 JavaScript 的所有字节都不等价。200KB 的脚本和 200KB 的图片所需要的代价差异很大。

并非所有字节都是等价的。除开原始的网络传输成本,200KB 的脚本和 200KB 的 JPG 所需要的代价大相径庭。

他们的下载时间可能一样,但处理起来却需要不同的成本。

JPEG 图像需要解码、光栅化,然后绘制在屏幕上。JavaScript 需要下载,然后解析、编译、执行—— 还有大量需要引擎完成的其它步骤。请注意,他们的成本并不相同。

成本变得重要的原因之一是因为移动端。

Mobile is a spectrum.

Mobile is a spectrum composed of cheap/low-end, median and high-end devices.

If we’re fortunate, we may have a high-end or median end phone. The reality is that not all users will have those devices.

They may be on a low-end or median phone, and the disparity between these multiple classes of devices can be quite stark due too; thermal throttling, difference in cache sizes, CPU, GPU — you can end up experiencing quite different processing times for resources like JavaScript, depending on the device you’re using. Your users on low-end phones may even be in the U.S.


“Insights into the 2.3 Billion Android Smartphones” by newzoo. Android has a 75.9% share of the global market with a predicted 300m more smartphones joining the market in 2018. Many of these will be budget Android devices.

Here’s a breakdown of how long it takes to parse JavaScript across a spectrum of hardware available in 2018:


Processing (parse/compile) times for 1MB of uncompressed JavaScript (<200KB minified and gzipped) manually profiled on real devices. (src)

At the top we have high-end devices, like the iPhone 8, which process script relatively quickly. Lower down we have more average phones like the Moto G4 and the <$100 Alcatel 1X. Notice the difference in processing times?

Android phones are getting cheaper, not faster, over time. These devices are frequently CPU poor with tiny L2/L3 cache sizes. You are failing your average users if you’re expecting them to all have high-end hardware.

Let’s look at a more practical version of this problem using script from a real-world site. Here’s the JS processing time for CNN.com:


JavaScript processing times for CNN.com via WebPageTest (src)

On an iPhone 8 (using the A11 chip) it takes nine seconds less to process CNN’s JavaScript than it does on an average phone. That’s nine seconds quicker that experience could get interactive.

Now that WebPageTest supports the Alcatel 1X (~$100 phone sold in the U.S, sold out at launch) we can also look at filmstrips for CNN loading on mid-lower end hardware. Slow doesn’t even begin to describe this:


Comparison of loading CNN.com, a JavaScript-heavy site, over 3G on mid-lower end hardware (source). The Alcatel 1X takes 65s to fully load.

This hints that maybe we need to stop taking fast networks and fast devices for granted.


Some users are not going to be on a fast network or have the latest and greatest phone, so it’s vital that we start testing on real phones and real networks . Variability is a real issue.

移动端是一个谱系。

移动端是一个包含了便宜/低端、中端和高端设备的谱系

如果运气好,我们可能会遇到一个中高端的手机。但实事上并非所有用户都有这么好的设备。

用户使用的可能是中低端的手机,而且各类设备之间也存在极大的差异;热节流、缓存大小差异、CPU、GPU —— 最终,处理资源的时间会像处理 JavaScript 一样存在较大的差异,这些都取决于所使用的设备。使用低端手机的用户甚至可能就在美国

newzoo 发表了“对 23 亿 Android 智能手机的观察分析”。Android 在全球占有 75.9% 的市场A份额。预计 2018 年至少还有 3 亿的智能手机进入市场。其中有大量的 Android 设备。

下面是 2018 年各种硬件设备下对 JavaScript 解析时间的分析:

处理 (解析/编译) 1MB 未压缩的 JavaScript (压缩和 gZip 处理后 < 200KB)所需要的时间,这些时间是在真实设备上手工测得。(来源)

最上面是像 iPhone8 这样的高端设备,处理 JavaScript 相对较快。下面是一些普通手机,比如 Moto G4 和低于 100 美元的 Alcatel 1X。注意到处理时间的差异了吗?

随着时间的推移,Android 手机越来越便宜,而不是更快。这些设置的 CPU 频率更高,L2/L3 缓存也小得可怜。如果你期待用户都使用高端设备,那么你的目标用户就会减少。

我们从一个真实的网站来实际看看这个问题。下面是 CNN.com 的 JS 处理时间:

CNN.com 上的 JavaScript 处理时间,来自 WebPageTest (来源)

iPhone 8 (使用 A11 芯片) 在处理 CNN 的 JavaScript 比说通手机快 9 秒。这 9 秒可以让增强用户体验。慢得甚至需要特别说明:

对于 CNN.com,这个大量使用 JavaScript 的网站,比较中低端硬件通过 3G 访问加载的情况(来源)。Alcatel 1X 花了 65秒 才完成加载。

这暗示我们应该停止使用快速的网络和快速的设备。

有一些用户不会使用快速的网络,或者没有最新最好的手机,所以我们有必要从实际的手机和实际的网络环境开始测试。易变性确实是个问题。

“Variability is what kills the User Experience” — Ilya Grigorik. Fast devices can actually sometimes be slow. Fast networks can be slow, variability can end up making absolutely everything slow.

When variance can kill the user experience, developing with a slow baseline ensures everyone (both on fast and slow setups) benefits. If your team can take a look at their analytics and understand exactly what devices your users are actually accessing your site with, that’ll give you a hint at what devices you should probably have in the office to test your site with.


Test on real phones & networks.

webpagetest.org/easy has a number of Moto G4 preconfigured under the “Mobile” profiles. This is valuable in case you’re unable to purchase your own set of median-class hardware for testing.

There’s a number of profiles set up there that you can use today that already have popular devices pre-configured. For example, we’ve got some median mobile devices like the Moto G4 ready for testing.

It’s also important to test on representative networks. Although I’ve talked about how important low end and median phones are, Brian Holt made this great pointit’s really important to know your audience.


“Knowing your audience and then appropriately focusing the performance of your application is critical” — Brian Holt (src)

Not every site needs to perform well on 2G on a low-end phone. That said, aiming for a high level of performance across the entire spectrum is not a bad thing to do.


Google Analytics > Audience > Mobile > Devices visualizes what devices & operating systems visit your site.

You may have a wide range of users on the higher end of the spectrum, or in a different part of the spectrum. Just be aware of the data behind your sites, so that you can make a reasonable call on how much all of this matters.

If you want JavaScript to be fast, pay attention to download times for low end networks. The improvements you can make there are: ship less code, minify your source, take advantage of compression (i.e., gzipBrotli, and Zopfli).


Take advantage of caching for repeat visits. Parse time is critical for phones with slow CPUs.


If you’re a back-end or full stack developer, you know that you kind of get what you pay for with respect to CPU, disk, and network.

As we build sites that are increasingly more reliant on JavaScript, we sometimes pay for what we send down in ways that we don’t always easily see.

“可变性是杀死用户体验的原因” -  Ilya Grigorik。快速设备实际上有时可能很慢。快速网络可能很慢,可变性最终会使一切变得缓慢。

当差异可能会破坏用户体验时,使用缓慢的基线进行开发可确保每个人(快速和慢速设置)都能获益。如果您的团队可以查看他们的分析并准确了解您的用户实际访问您网站的设备,那么您将会提示您应该在办公室中使用哪些设备来测试您的网站。

                                            测试真实的手机&网络。

webpagetest.org/easy在“移动”配置文件下预先配置了许多Moto G4。如果您无法购买自己的中等级硬件进行测试,这将非常有用。

这里设置了许多配置文件,您可以使用这些配置文件已预先配置了常用设备。例如,我们有一些中等移动设备,如Moto G4准备测试。

在代表性网络上进行测试也很重要。虽然我已经谈到了低端手机和中位手机的重要性,但布莱恩霍尔特提出了这个观点:了解你的观众非常重要。

“了解您的受众,然后适当地关注应用程序的性能至关重要” -  Brian Holt(src)

并非每个站点都需要在低端手机上的2G上表现良好。也就是说,在整个频谱范围内实现高水平的性能并不是一件坏事。

谷歌分析>观众>移动设备>设备 可视化设备&操作系统访问您网站的位置。

您可能在频谱的较高端或频谱的不同部分拥有广泛的用户。请注意您网站背后的数据,以便您可以合理地调用所有这些内容。

如果您希望JavaScript快速,请注意低端网络的下载时间。您可以进行的改进包括:减少代码,缩小源代码,利用压缩(即gzip,Brotli和Zopfli)。

利用缓存重复访问。对于CPU速度慢的手机,解析时间至关重要。

如果您是后端或全堆栈开发人员,您知道您可以获得有关CPU,磁盘和网络的费用。

当我们构建越来越依赖JavaScript的网站时,我们有时会以我们并不总是容易看到的方式支付我们发送的内容。

How to send less JavaScript

The shape of success is whatever let’s us send the least amount of script to users while still giving them a useful experience. Code-splitting is one option that makes this possible.


Splitting large, monolithic JavaScript bundles can be done on a page, route or component basis. You’re even better setup for success if “splitting” is the default for your toolchain from the get-go.

Code-splitting is this idea that, instead of shipping down your users a massive monolithic JavaScript bundle — sort of like a massive full pizza — what if you were to just send them one slice at a time? Just enough script needed to make the current page usable.

Code-splitting can be done at the page level, route level, or component level. It’s something that’s well supported by many modern libraries and frameworks through bundlers like webpack and Parcel. Guides to accomplish this are available for ReactVue.js and Angular.


Adding code-splitting in a React app using React Loadable — a higher-order component that wraps dynamic imports in a React-friendly API for adding code-splitting to your app at a given component.

Many large teams have seen big wins off the back of investing in code-splitting recently.


In an effort to rewrite their mobile web experiences to try to make sure users were able to interact with their sites as soon as possible, both Twitter and Tinder saw anywhere up to a 50% improvement in their Time to Interactive when they adopted aggressive code splitting.

Stacks like Gatsby.js (React), Preact CLI, and PWA Starter Kit attempt to enforce good defaults for loading & getting interactive quickly on average mobile hardware.

Another thing many of these sites have done is adopted auditing as part of their workflow.


Audit your JavaScript bundles regularly. Tools like webpack-bundle-analyzer are great for analyzing your built JavaScript bundles and import-cost for Visual Code is excellent for visualizing expensive dependencies during your local iteration workflow (e.g. when you `npm install` and import a package)

Thankfully, the JavaScript ecosystem has a number of great tools to help with bundle analysis.

怎样才可以发送更小的 JavaScript

无论如何,只要我们能让发送出去的 JavaScript 最小,同还还能让用户有较好的体验,那么成功就在眼前。Code-splitting 就是一个能实现这一愿望的选择。

基于页面、路由或组件拆分巨大而完整的 JavaScript 包。如果“splitting”一开始就用在你的工具链中,你离成功就更近一步。

Code-splitting 的思想是这样的:不是向用户发送一个巨大的单个 JavaScript 文件 —— 就像一个巨大的披萨一样 —— 如果每次只给他们一块怎么样?只要有足够多片(但不是全部 —— 译者注)就能让当前页面跑起来。

Code-splitting 可以工作在页面、路由或组件级别。这对于很多现代的库和框架来说是件好事,这些库或框架可能通过 webpack 和 Parcel 生成脚本包。按照指南,可以将其用于 React、 Vue.js 和 Angular

在 React 应用中通过 React Loadable  添加 code-splitting。React Loadable 是一个高阶组件,它可以将动态导入封装在对 React  友好的 API 中,将 code-splitting 应用于给定的组件。

最近,很多大型团队看到了胜利背后的 code-splitting。

基于希望用户能快速进入交互的需求,Twitter 和 Tinder 积极采用代码分割方法来重写他们的移动 Web 体验,其交互性能提高了 50%。

像 Gatsby.js (React)、Preact CLI 和 PWA Starter Kit,通过尝试,在普通的移动硬件上达到了快速加载以及快速入进交互的效果。

这些网站还做了一件事情,就是采用审查,使其成为工作流程的一部分。

定期审查 JavaScript 包。像 webpack-bundle-analyzer 这样的工具非常适合用来分析构建出来的 JavaScript 包,以及可视代码的导入成本,这对于将本地化迭代工作流程错综复杂的依赖关系可视化非常有效。(比如,使用 `npm install` 导入包时)

值庆幸的是,JavaScript 生态系统中有大量优秀的工具可用于包分析。

返回顶部
顶部