[译]the cost of javascript in 2018(1)
前言
为了构建交互性网站,我们需要发送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的表现对网站的影响(私以为,不一定正确),或者说前面的铺垫太长太久,策略比较靠后。不过我认为这样讲清来龙去脉的文章会更好一点,好文共享吧。
[译]the cost of javascript in 2018(1)的更多相关文章
- ( 译、持续更新 ) JavaScript 上分小技巧(四)
后续如有内容,本篇将会照常更新并排满15个知识点,以下是其他几篇译文的地址: 第一篇地址:( 译.持续更新 ) JavaScript 上分小技巧(一) 第二篇地址:( 译.持续更新 ) JavaScr ...
- ( 译、持续更新 ) JavaScript 上分小技巧(三)
最近家里杂事较多,自学时间实在少的可怜,所以都在空闲时间看看老外写的内容,学习之外顺便翻译分享~等学习的时间充足些再写写自己的一些学习内容和知识点分析(最近有在接触的:复习(C#,SQL).(学习)T ...
- ( 译、持续更新 ) JavaScript 上分小技巧(二)
考虑到文章过长,不便于阅读,这里分出第二篇,如有后续,每15个知识点分为一篇... 第一篇地址:( 译.持续更新 ) JavaScript 上分小技巧(一) 第三篇地址:( 译.持续更新 ) Java ...
- ( 译、持续更新 ) JavaScript 上分小技巧(一)
感谢好友破狼提供的这篇好文章,也感谢写这些知识点的作者们和将他们整理到一起的作者.这是github上的一篇文章,在这里本兽也就只做翻译,由于本兽英语水平和编程能力都不咋地,如有不好的地方也请多理解体谅 ...
- (译)详解javascript立即执行函数表达式(IIFE)
写在前面 这是一篇译文,原文:Immediately-Invoked Function Expression (IIFE) 原文是一篇很经典的讲解IIFE的文章,很适合收藏.本文虽然是译文,但是直译的 ...
- 【JavaScript】【译】编写高性能JavaScript
英文链接:Writing Fast, Memory-Efficient JavaScript 很多JavaScript引擎,如Google的V8引擎(被Chrome和Node所用),是专门为需要快速执 ...
- 【译】写好JavaScript条件语句的5个技巧
译文 当我们写JavaScript代码时,经常会用到到条件判断处理,这里有5个技巧能使你写出更好.更简洁的条件语句. 1.使用Array.includes处理多种条件 让我们来看一下的例子: // c ...
- The Cost of JavaScript --------引用
tl;dr: 想要保持页面的快速运行,你需要仅加载当前页面所需的 JavaScript 代码.优先考虑用户所需,之后运用代码分离懒加载其他内容. Is it happening - 在这个时期,你可以 ...
- 2018 Python开发者大调查:Python和JavaScript最配?
在2018年秋季,Python软件基金会与JetBrains发起了年度Python开发者调查. 报告的目的是寻找Python领域的新趋势,帮助开发者深入了解2018年Python开发者的现状. 该报告 ...
随机推荐
- Confluence 6 升级自定义的站点和空间获得你的自定义布局
我们建议你在对站点进行布局修改的时候,你需要为你修改的 Confluence 站点或空间布局保留所有的修改记录. 如果没有的话,你应该可以通过下面的办法找到你的自定义修改.这个方法将会把你对全部网站和 ...
- vue-cli3初尝试之路径别名配置
let path = require('path') function resolve(dir) { return path.join(__dirname, dir) } module.exports ...
- 用json获取拉钩网的信息
class LaoGo(object): def __init__(self): self.url="http://www.lagou.com/lbs/getAllCitySearchLab ...
- Django框架第一篇基础
一个小问题: 什么是根目录:就是没有路径,只有域名..url(r'^$') 补充一张关于wsgiref模块的图片 一.MTV模型 Django的MTV分别代表: Model(模型):和数据库相关的,负 ...
- linux下mysql源码安装
参考链接:http://blog.csdn.net/zqtsx/article/details/9378703 下载mysql安装包, 不会下载点这里 地址:ftp://mirror.switch.c ...
- C++ Primer 笔记——类成员指针
1.当我们初始化一个成员指针或为成员指针赋值时,该指针并没有指向任何数据.成员指针指定了成员而非成员所属的对象,只有当解引用成员指针时,我们才提供对象信息. 2.和普通的函数指针类似,如果成员存在重载 ...
- C#动态系统托盘图标
C#动态系统托盘图标 利用timer组件定时执行变化. using System; using System.Windows.Forms; namespace DynamicStockIcon { p ...
- SqlServer 四大排名函数(ROW_NUMBER、RANK、DENSE_RANK、NTILE)简介
CREATE TABLE [dbo].[Order]( [ID] [int] IDENTITY(1,1) NOT NULL, [UserId] [int] NOT NULL, [TotalPrice] ...
- Android Studio编译OsmAnd出现警告:GeoPointParserUtil.java使用或覆盖了已过时的 API。有关详细信息请使用-Xlint:deprecation重新编译
[背景] 之前折腾: [记录]Android Studio中导入OsmAnd并编译 期间,遇到了编译警告: 1 2 3 4 5 :OsmAnd-java:compileJava 注: E:\crifa ...
- Notepad++文件自动更新