写点什么

JavaScript 的成本

  • 2018-01-02
  • 本文字数:3946 字

    阅读完需:约 13 分钟

在建立那些严重依赖于 JavaScript 网站的时候,有时我们会为自己发送的内容付出一些隐形的成本。在本篇文章中,我会介绍一些可以帮助你提升网站在移动设备上加载和运行速度的实用规则

tl;dr:更少的代码 = 更少的解析 / 编译 (parse/compile)+ 更少的传送 + 更少的解压缩

网络

大多数开发人员考虑 JavaScript 成本的时候,考虑的都是下载和执行成本。通过线路发送的 JavaScript 字节越多,所需时间就越长,用户连接就越慢。

即使是在发达国家,这也可能是一个问题,因为用户实际上用的有效网络连接类型可能并不是 3G、4G 或者 Wifi。表面上你可能连的是咖啡店的 Wifi,但实际上连到的是只有 2G 速度的蜂窝热点。

你可以通过以下的几种方式来降低 JavaScript 的网络传输成本:


(减少向用户发送 JavaScript 量的最佳做法。)

解析 / 编译

下载成功后,JavaScript** 绝大部分的时间都消耗在 JS 引擎对下载代码的解析 / 编译 ** 上。在 Chrome DevTools 中,解析和编译是下面性能面板(Performance panel)中黄色“脚本”时间的一部分。

Bottom-Up/Call Tree 允许我们去确切地查看解析 / 编译所用时间:


Chrome DevTools 性能面板下级菜单 >Bottom-U。启动 V8 的 Runtime Call Stats,就能看到不同阶段的时间消耗,比如解析 / 编译所用时间。

但是,这为什么会是个问题?

耗费很长的时间在解析 / 编译代码上,会严重延迟用户与你网站的交互时间。你发送的 JavaScript 越多,在网站实现交互前所用的解析 / 编译的时间就会越长

即使是同样多的字节,浏览器处理 JavaScript 也会比处理等大小的图片和网页字体消耗更高的成本——Tom Dale

相比于 JavaScript,处理等字节的图片所需要的时间成本很高(因为图片仍需要解码!)但是在一般的移动设备上,反而是 JS 更有可能对页面的交互产生负面的影响。


(JavaScript 字节和图像字节耗费的时间成本不同。图像通常不会阻塞主线程,也不会在解码和光栅化的时候阻止接口进行交互。然而 JS 会因为解析、编译和执行的时间消耗阻滞交互性。)

当我们说解析和编译的速度变慢的时候,要注意具体的网络端和设备端的情况,在这里我们针对的是普通手机。普通用户所使用手机的 CPU 和 GPU 速度比较慢,没有 L2/L3 缓存,甚至可能会有内存限制。

网络功能和设备功能并不总是相匹配的。有速度惊人的光纤连接的用户不一定会有最好的 CPU 来解析和评估发送到他们的设备的 JavaScript。反过来也是如此…你可能有糟糕的网络连接,但却有快速的 CPU。 - Kristofer Baxter,LinkedIn

JavaScript Start-up Performance 一文中,我曾提到过在低端和高端硬件上解析~1MB 解压缩过(简单)的 JavaScript 所需要消耗的时间。市面上的普通手机和运行速度最快的手机相比,解析 / 编译代码的所用的时间会有 2-5 倍的差距。


(在不同级别的台式和移动设备上解析 1MB 的 JavaScript 包(经 gzip 压缩,大小约为 250KB )。当分析解析成本时,我们需要考虑的是解压后的数据量,例如〜250KBgzip 压缩过的 JS 解压缩后约为〜1MB 的代码。)

那解析 / 编译真实网站的时间差异又会是怎样呢,比如 CNN.com 网站?

在高端的 iPhone 8 上解析 / 编译 CNN 网站的 JS 大约花费了 4 秒,相比于普通手机(Moto G4)的 13 秒左右。这可以显著地影响用户与 CNN 网站实现完全交互的速度。


(苹果公司的 A11 仿生芯片和更普通的 Android 硬件中的 Snapdragon 617 的解析时间上的性能比较

这就突出了在普通硬件(比如 Moto G4)上测试的重要性,而不仅仅是在自己恰好有的手机上测试。基于 _ 自己 _ 客户原有的设备和网络条件来进行优化是很重要的。

分析可以使你更加深入了解自己真实客户访问网站所用的移动设备的级别和这些设备 CPU/GPU 的局限性。

我们真的发送了太多的 JavaScript 了吗?呃…真有可能:)

用 HTTP Archive(qian500K 站点)来分析移动设备上 JavaScript 的状态时,我们可以看到,50%的站点需要 14 秒才能取得交互。这些网站光是用来解析和编译 JS 的时间就长达 4 秒。

考虑到获取和处理 JS 和其他资源所耗费的时间,也就不奇怪用户可能需要在页面可用之前等待一段时间了。我们绝对可以在这个方面做的更好。

从网页中删除不必要的 JavaScript 可以减少传输时间、CPU 密集型解析和编译以及潜在的内存消耗,同时也有助于加快网页的交互速度。

执行时间

不光是解析和编译会有时间成本。执行 JavaScript(在解析 / 编译之后运行代码)也是需要在主线程上进行的操作之一。长的执行时间也会延迟用户与你网站的交互时间。

如果脚本执行的时间超过了 50ms,那么延迟交互的时间将会是下载、编译和执行 JS 所需时间的总和——Alex Russell

为了解决这个问题,可以将 JavaScript 脚本分为几个小块来执行,以避免锁定主线程。探索一下是否可以减少脚本执行过程中进行中工作量的可能性。

减少 JavaScript 交付成本的模式

当你试图降低 JavaScript 解析 / 编译和网络传输所用时间时,类似于基于路由分块和 PRPL 这些模式也会有用。

PRPL 是一种通过激进的(aggresive)代码分割和缓存来优化交互性的模式:

为了能将PRPL 的影响以视觉化方式表现出来。

我们用V8 引擎中的Runtime Call Stats 分析了流行移动网站和progressive Web Apps(PWA)的加载时间。正如我们所看到的,解析部分(用橙色表示)是很多网站页面加载时产生显著时间消耗的部分。

Wego 网站就使用了 PRPL 来保持较低的路由解析时间,让页面交互得以快速的进行。以上的很多站点都试图采用代码分割和性能预算来降低 JS 的消耗。

JavaScript 的其他消耗

JavaScript 还可以通过其他方式来影响页面性能:

  • 存储。页面可能会因为垃圾回收(GC,garbage colleciton),页面可能会出现画面中断卡顿(junk)和暂停。因为当一个浏览器回收内存的时候,JS 的执行也会被中止,所以经常回收垃圾的浏览器会比我们想象中的更频繁地中止 JS 的执行。在这种情况下,可以通过避免内存溢出和频繁内存回收来保持页面的流畅。
  • 在运行时,长时间的运行 JavaScript 会阻塞主线程,导致页面没有响应。这种情况下,可以将脚本的工作量分成多个小的板块(具体可用 requestAnimationFrame() 或者 requestIdleCallback() 进行任务调度)来执行,以此减少页面响应的问题。

Progressive Bootstrapping

很多网站将优化内容可视性作为保证交互性所需代价的一部分。为了在 JavaScript 有大体积包体时改善首屏性能,开发人员有时会先用服务器端渲染帮助客户提前看到页面内容,然后再在 JavaScript 最终执行完成后“升级”附加上事件处理程序。

但是值得注意的是,这样做也是有代价的。你 1)通常会发送一个更大的 HTML 响应来增加交互性,2)在一段时间内,用户会处在一半的页面交互体验缺失的奇怪状况下,直到 JavaScript 处理完成。

Progressive Bootstrapping 或许会是一个更好的处理方式。浏览器请求一个最少化的功能页面(仅由当前路由所需要的 HTML/JS/CSS 组成)。当有更多的资源请求的时候,应用程序则可以懒加载(lazy-load)和解锁更多的功能。


Progressive Bootstrapping visual by Paul Lewis

仅加载可视区域内的代码是其中的关键。PRPL 和 Progressive Bootstrapping 模式均可以用来实现这一点。

结论

传输脚本的大小对低端网络至关重要,而解析时间对于 CPU 有局限性的设备很重要。降低传输脚本的大小和减少解析消耗时间是有必要的。

有团队发现采用严格的性能预算可以成功降低他们 JavaScript 的传输和解析 / 编译的时间消耗。具体可参照 Alex Russell 的“ Can You Afford It?: Real-world Web Performance Budgets ” 一文中关于移动设备预算的指导。


(考虑一下在我们所做的架构决策下,JS 有多大的空间可以让我们的应用程序具有逻辑)

如果你正在建一个用于移动设备上的站点,请尽可能的在代表性硬件上开发,保持较低的 JavaScript 解析 / 编译的时间成本,并采用性能预算来确保团队对自身 JavaScript 的成本关注。

更多相关学习


(点击观看视频,作者 2017 年在 Chrome Dev Summit 上的演讲,其中涵盖了本文内容,其后就 Pinterest 和 Tinder 这样的制作网站进行了性能案例研究

作者感谢了来自 Nolan Lawson,Kristofer Baxter 和 Jeremy Wagner 的反馈。

原文链接: The Cost Of JavaScript

感谢徐川对本文的审校。

2018-01-02 17:313650

评论

发布
暂无评论
发现更多内容

数据库审计部署方式有哪些?哪种比较好?

行云管家

数据库 数据库审计 数据库审计部署

小程序表单组件-1

小恺

7月月更

一招,让停车管理不再难

天翼云开发者社区

数字化 云平台

易观分析加入智能投研技术联盟,共促行业数智化发展

易观分析

易观新闻

Python|分析QQ群聊信息,记录词频并制作词云

AXYZdong

Python 7月月更

java零基础入门-多态

喵手

Java 7月月更

大数据ZooKeeper(一):基本知识和集群搭建

Lansonli

大数据 zookeeper 7月月更

leetcode 455. Assign Cookies 分发饼干(简)

okokabcd

LeetCode 数据结构与算法 贪心算法

项目进度管理和风险管理记录

老猎人

数据库审计和日志审计的三大区别分析

行云管家

数据库 日志 日志审计 数据库审计

大数据环境搭建:​​​​​​​​​​​​​​​​​​​​​Hadoop编译和分布式环境搭建

Lansonli

大数据 hadoop 环境搭建 7月月更

火眼金睛,天翼云助力打造城市视觉中枢

天翼云开发者社区

大数据 云平台

大数据培训Spark数据倾斜问题的解决方法

@零度

spark 大数据开发

关于微软 Edge 浏览器的 Tracking Prevention 特性在 Angular 应用中的影响

汪子熙

JavaScript typescript Web web开发 7月月更

APISIX 如何与 Hydra 集成,搭建集中认证网关助力企业安全

API7.ai 技术团队

云原生 网关 身份验证 APISIX 网关

揭露数据不一致的利器 —— 实时核对系统

Shopee技术团队

数据分析 后端

告别缺电焦虑!充电桩装上“智慧大脑”

天翼云开发者社区

云主机 云平台

2022数十位Java架构师汇总产出,最新25个技术栈“Java面经”

程序知音

Java 程序员 面试 后端 八股文

JAVA编程规范之命名风格

源字节1号

软件开发

百家号基于AE的视频渲染技术探索

百度Geek说

视频 视频渲染

Python 入门指南之标准库概览

海拥(haiyong.site)

7月月更

数据也能进超市

天翼云开发者社区

云计算 大数据 云平台

五个核心能力打造普惠金融商业化发展模式

易观分析

普惠金融

【愚公系列】2022年7月 Go教学课程 010-数据类型之布尔型和字符类型

愚公搬代码

7月月更

LeetCode-119. 杨辉三角II(java)

bug菌

Leet Code 7月月更

天翼云携手华为,强强联合,共创数据存储新生态

天翼云开发者社区

存储 数字化

为安全而生!云安全漫谈开讲啦

云安全 云计算运维

『51单片机』十分钟学会定时器

謓泽

7月月更

2022年中国互联网医疗年度盘点

易观分析

互联网医疗

阿里云第四届全球数据库大赛火热开赛,40万奖金广纳英才

科技热闻

内行,阿里大牛离职带出内部“高并发系统设计”学习手册

程序知音

Java 阿里巴巴 程序员 后端 高并发

JavaScript的成本_JavaScript_Addy Osmani_InfoQ精选文章