前言
为了构建交互性网站,我们需要发送js给我们的用户,但很多情况下,我们使用了太多js。
在移动端,经常看到只加载了个点击链接或者滚动不了的情况。
实话说,js仍然是移动端最昂贵的资源,因为其在很大程度上会延迟交互(即交互要在js资源生效之后才可进行)。下图展现了不同手机处理js的耗时,高端机和低端机的差别是相当的大,而用户的机型不可控,所以必须要去优化我们的加载策略。
今天我们将展示给大家一些高效加载js的策略,以便提升用户的体验。
一、tl;dr:
为保持快速响应,只加载当前页面相关的js
优先考虑用户所需要的,可以通过code-spliting懒加载剩余的资源,这样可以在加载和执 行上给我们很大的提升,默认情况下基于路由的code-spliting是最佳实践(game-changers)
拥抱性能预期并学会与之相处
移动端而言,压缩之后的代码小于170k。未压缩的仍然有0.7m。预期对成功是重要的。但是优化也不是只着重于局限于代码上的优化,团队风格、代码结构和执行,都是很重要的。没有预期目标的开发会带来性能变差和失败的风险学习如何审视和优化我们的js bundles文件
我们很可能加载了全部的库,尽管只使用了一小部分,并不需要其对于浏览器的polyfill和重复代码每次交互都会开始新一次的Time-to-Interactive,基于此环境进行优化
传输文体体积对于低端网络设备和计算密集型设备而言是至关重要的如果客户端的代码对用户体验无益,重新审视是否必须
可能服务端渲染确实更加快速,但更需要为具体页面使用的客户端框架斟酌一番,如果没有详细考虑,那么将是一场灾难。二、网络因用户体验而臃肿
当用户访问我们的网站时,我们可能发送了太多的文件,很大一部分是js脚本。从浏览器的视角来看,就像下面这张图一样。
尽管我十分喜欢js,但其始终是我们网站中最昂贵的一部分,下面将会阐述为什么我这样认为。
当今的网页接收的压缩之后的js的资源大小平均为350kb,解压之后需要浏览器处理的大小超过1m。
注意:不确定你的js bundle包是否影响了网站与用户的交互,用Lighthouse试试看
处理这么多的js脚本,知道移动设备具备可交互性,大概要超过14s的时间。
主要影响因素在于,移动设备上加载资源和cpu执行代码的时间,当然越短越好。
那么看下当前的网络状态:
上面的图表展示了,全球来看不同地图的4g可用程度和网络的平均速度。可以看到大部分的国家和地区,移动网络是比我们想象中要差的(图上来看,我国真的是相当落后)。
对于中间网页来说并不仅仅是在350k的js需要下载之外,当下主流网站会下载更多的js脚本。
不管是桌面还是移动端,我们都要达到天花板了。有些网站会发送上兆的代码给浏览器执行。那么问题来了,我们是否能承受如此多的js代码
三、js的开销
注意,如果加载太多的js,考虑code-splitting来拆分包,或者使用tree-shaking来减小js文件的paypload(reducing JS payloads using tree-shaking)
网站的脚本一般包括以下几类:
- 客户端的框架或者ui库
- 一个状态管理工具(例如 redux)
- Polyfills(对于现代浏览器来说并不需要)
- 完整的库或者按需加载的部分(例如完整的lodash, Moment + locales)
- 一套ui组件(例如buttons headers)
加载页面的过程像电影带一样分为三个重要阶段: Is it happening(是否发生), Is it useful(是否有用),is it usable(是否可用)。个人理解这里的后两者的差别,在于有用即有意义信息是否展示,可用只是否可交互。具体如下图所示:
根据上面的图示,更容易理解
Is it happening (是否发生)
当前时间点,是否有响应或者提示信息显示在页面上(导航是否开始,服务端是否响应)
Is it useful(是否有用)
此时,应该已经显示了文本或者内容,该过程用户可以获取信息
is it usable(是否可用)
此时,用户应该可以进行正常的交互操作,即为可用。
在前面就提到了可交互性(interactive),到底什么是可交互性呢(原作者的图真的十分形象,一眼就看到问题所在):
对一个页面而言,可交互性指的是快速对用户的输入做出相应,一个小体积的脚本payload可以让这个阶段快速出现。
无论是点击链接还是滚动屏幕,如果用户得不到相应的真是反馈,那么用户会抓狂的。
这种情况经常发生在服务端渲染的时候,我们会发送过多的js来重写以实现额外的功能(例如事件处理等)
当浏览器运行很多我们需要的事件时,极大可能会在主线程里来实现,可是用户的输入操作也在主线程中响应。
将load过多的js放在主线程中进行(例如通过script标签)正是一个问题。所以将js放入webworker或者在service worker中将会避免这种影响。(译者注,即将耗时工作从主线程中分离)。
尽可能的避免阻塞主线程,更多可以查看Why web developers need to care about interactivity
当下,我们正看到兄弟团队在不同类型网站上饱受过多js阻塞交互之苦。
下面是一些谷歌搜索的例子:你可以开始点击ui,但如果页面加载太多js,在真实响应之前,可能会有一些延迟。当然都希望页面能够尽快可交互。
通过观察谷歌新闻在不同机器上的可交互时间,发现不同设备之间的巨大差异,高端机在7s以内,而低端设备需要55s,那么问题来了,具体的优化的目标应该定在哪里呢?
具体而言,作者认为基准应该是中等设备在慢3g网络下5s内可交互。如果说你的用户都在wifi下,那样也不现实,适应性是重要的。
下面可以看下通过减少js加载降低Time-to-Interactive的例子:
- Pinterest 将 JavaScript bundle 从 2.5MB 降低到小于 200KB,而 Time-to-Interactive 时间则从23秒降到5.6s. 收入增长44%,注册增长753%,移动互联网周活跃用户增长103%。
- AutoTrader 将 JavaScript bundle 大小降低了 56% 并将达到 Time-to-Interactive 的时长缩短了一半。
- Nikkei 将 JavaScript bundle 大小降低了 43% 并将 Time-to-Interactive 耗时缩短了13秒。
Let’s design for a more resilient mobile web that doesn’t rely as heavily on large JavaScript payloads.
我们需要设计一个不依赖于大量js文件的高适应性网站
可交互性影响很多事情,同样也被很多因素影响,例如移动数据加载、WiFi或者旅途中间歇性连接。这些情况下,你依然有很多js去解析。那么用户可能不会等待。
所以我们需要去优化,在优化之前我们需要了解下,为什么js如此的昂贵。但是原文毕竟太长,暂且放松一下告一段落,太长的文章大家也不会有耐心读完,后事听下回。
结束语
原文
The Cost of JavaScript In 2018
很多时候我们都是为了优化而优化,看到业界认同的优化策略就拿来用,可能少了那么一点思考。为什么,如何用,是否适合自己,正好看到这篇详细的文章,可能作者有点啰嗦,事无巨细的在强调过多js的表现对网站的影响(私以为,不一定正确),或者说前面的铺垫太长太久,策略比较靠后。不过我认为这样讲清来龙去脉的文章会更好一点,好文共享吧。