当前位置: 首页 > 科技观察

关注JavaScript的成本

时间:2023-03-18 14:32:09 科技观察

在构建严重依赖JavaScript的网站时,有时我们会为发送的内容支付一些隐性成本。在这篇文章中,我将介绍一些实用的规则,可以帮助您使您的网站在移动设备上加载和运行得更快。tl;dr:更少的代码=更少的解析/编译(parse/compile)+更少的传输+更少的网络解压大多数开发人员认为JavaScript的成本是下载和执行成本。通过网络发送的JavaScript字节越多,花费的时间就越长,用户的连接速度就越慢。即使在发达国家,这也可能是个问题,因为用户实际使用的网络连接类型可能不是3G、4G或Wifi。您可能看起来连接到咖啡店的Wi-Fi,但实际上连接到速度仅为2G的蜂窝热点。您可以通过多种方式降低JavaScript的网络传输成本:仅传输用户需要的代码。代码拆分可用。优化的压缩代码(ES5的Uglify,ES2015的babel-minify或uglify-es)高度压缩(使用Brotli~q11、Zopfli或gzip)。Brotli的压缩率比gzip的好。它可以帮助CertSimple在压缩后的JS字节大小上节省17%,并帮助LinkedIn减少4%的加载时间。删除无用的代码。使用ChromeDevTools代码覆盖功能来查找未使用的JS代码。对于代码缩小,请参阅tree-shaking、ClosureCompiler的高级优化和微调库插件,如lodash-babel-plugin,或Webpack的ContextReplacementPlugin,用于Moment.js等库。使用babel-preset-env和browserlist来避免现代浏览器中现有的转译。高级开发人员可能会发现仔细分析Webpack包可以帮助他们识别和调整不必要的依赖项。缓存HTTP代码以减少网络流量。确定脚本的最佳缓存时间(例如:max-age)并提供身份验证令牌(Etag)以避免发送未更改的字节。使用ServiceWorker缓存一方面可以让应用组网更加灵活,另一方面也可以让你快速访问像V8代码缓存这样的特性。对于长期缓存,您可以了解Webpack文件名哈希。(减少发送给用户的JavaScript量的最佳方式。)在解析/编译和下载成功后,JavaScript**大部分时间用于解析/编译**JS引擎下载的代码。在ChromeDevTools中,解析和编译是下面性能面板中黄色“脚本”时间的一部分。Bottom-Up/CallTree让我们可以准确查看解析/编译所花费的时间:(ChromeDevTools性能面板子菜单>Bottom-U。启动V8的RuntimeCallStats,可以看到不同阶段的时间消耗,例如解析/编译所花费的时间。)但为什么这是一个问题?花很长时间解析/编译代码会严重延迟用户与您网站的交互。您发送的JavaScript越多,在网站变为交互式之前解析/编译所需的时间就越长。即使字节数相同,浏览器处理JavaScript也会消耗比处理相同大小的图像和网页字体更高的成本——TomDale与JavaScript相比,处理等字节图像的时间成本非常高(因为图像仍然需要解码!)但在一般的移动设备上,JS更可能对页面的交互产生负面影响。(JavaScriptbytes和imagebytes的时间成本是不一样的,images通常不会阻塞主线程,也不会在decode和rasterizing的时候阻止界面交互。但是JS会阻塞,因为解析,编译,编译都比较耗时executing.interactivitylag.)当我们说解析编译速度变慢的时候,要注意网络端和设备端的具体情况。这里我们针对的是普通手机。普通用户使用的手机CPU和GPU速度较慢,没有L2/L3缓存,甚至可能有内存限制。网络功能和设备功能并不总是匹配。拥有超快光纤连接的用户不一定拥有最好的CPU来解析和评估发送到他们设备的JavaScript。反之亦然……您的互联网连接可能很差,但CPU速度很快。–KristoferBaxter,LinkedIn在JavaScript启动性能中,我提到了在低端和高端硬件上解析~1MB的解压缩(简单)JavaScript所花费的时间。与市面上最快的手机相比,解析/编译代码的时间要长2-5倍。(一个1MB的JavaScriptbundle(gzip-compressed~250KB)在各种级别的桌面和移动设备上被解析。在分析解析成本时,我们需要考虑解压后的数据量,例如~250KBgzip压缩后的JS~1MB代码在解压时.)那么解析/编译真实网站的时间差又如何呢,比如CNN.com?为CNN网站解析/编译JS在高端iPhone8上花费了大约4秒,而普通手机(MotoG4)大约需要13秒。这会显着影响用户与CNN网站充分互动的速度。(Apple的A11Bionic芯片与Snapdragon617在更常见的Android硬件上的性能比较。这凸显了在常见硬件(例如MotoG4)上进行测试的重要性,而不仅仅是在您碰巧拥有它时进行测试。在移动设备上进行测试手机,根据客户原有设备和网络情况进行优化非常重要。分析可以让您更深入地了解您的真实客户访问网站所使用的移动设备的水平以及这些设备CPU/GPU的局限性.ArewereallysendingtoomuchJavaScript?呃...有可能:)当使用HTTPArchive(qian500K站点)分析移动设备上JavaScript的状态时,我们可以看到50%的站点需要14秒来获取交互.这些网站仅仅解析和编译JS就需要4秒的时间。考虑到获取和处理JS和其他资源所需的时间,用户可能需要等待一段时间才能获得页面也就不足为奇了。我们绝对可以在这方面做得更好。从网页中去除不需要的JavaScript可以减少传输时间、CPU密集型解析和编译以及潜在的内存消耗,同时也有助于加快网页的交互速度。执行时间不仅解析和编译有时间成本。执行JavaScript(解析/编译后运行代码)也是需要在主线程上发生的事情之一。较长的执行时间也会延迟用户与您网站的交互。如果脚本的执行时间超过50ms,延迟交互的时间就是下载、编译和执行JS所需时间的总和——AlexRussell可以通过将JavaScript脚本分成几个小块执行,来解决这个问题,避免锁定主线程。探索在脚本执行期间减少正在进行的工作量的可能性。降低JavaScript交付成本的模式当您尝试减少JavaScript解析/编译和网络传输时间时,基于路由的分块和PRPL等模式也很有用。PRPL是一种通过积极的代码拆分和缓存来优化交互性的模式:为了可视化PRPL的影响。我们使用V8引擎中的运行时调用统计分析了流行移动网站和渐进式Web应用程序(PWA)的加载时间。正如我们所看到的,解析部分(以橙色表示)是许多网站页面加载中非常耗时的部分。Wego网站使用PRPL来保持较低的路由解析时间并允许页面交互快速进行。上述许多站点都尝试使用代码拆分和性能预算来减少JS消耗。JavaScript的其他消耗JavaScript可以通过其他方式影响页面性能:存储。页面可能会受到垃圾回收(GC,garbagecolleciton),页面可能会出现图片中断(junk)和暂停。因为当浏览器回收内存的时候,JS的执行也会被挂起,所以频繁收集垃圾的浏览器会比我们想象的更频繁地挂起JS执行。在这种情况下,可以通过避免内存溢出和频繁的内存回收来保持页面流畅。在运行时,长时间运行JavaScript会阻塞主线程,导致页面无响应。这种情况下,可以将脚本的工作量分成多个小块(具体可以使用requestAnimationFrame()或requestIdleCallback()进行任务调度)来执行,从而减少页面响应问题。渐进式引导许多网站优化内容可见性作为确保交互性成本的一部分。为了在JavaScript包体较大时提高首屏性能,开发人员有时会使用服务器端渲染来帮助客户提前看到页面内容,然后在JavaScript最终执行后“升级”以附加事件处理程序。但值得注意的是,这样做是有代价的。你1)通常会发送一个更大的HTML响应来增加交互性,2)在一段时间内,用户会处于页面交互体验缺失一半的奇怪情况,直到JavaScript处理完成。ProgressiveBootstrapping可能是处理它的更好方法。浏览器请求一个最低限度的功能页面(仅包含当前路由所需的HTML/JS/CSS)。当请求更多资源时,应用程序可以延迟加载(lazy-load)并解锁更多功能。ProgressiveBootstrappingvisualbyPaulLewis只加载可视区域内的代码是这里的关键。PRPL和ProgressiveBootstrapping模式都可以用来实现这一点。结论传输脚本大小在低端网络上很重要,而解析时间在CPU密集型设备上很重要。有必要减小传输脚本的大小并减少解析时间。一些团队发现采用严格的性能预算可以成功减少他们的JavaScript传输和解析/编译时间消耗。(考虑到我们做出的架构决策,JS在我们的应用程序中有多少逻辑空间)如果您正在为移动设备构建站点,请尽可能在具有代表性的硬件上开发,保持JavaScript解析/编译的时间成本低,并使用性能预算来确保团队关注他们自己的JavaScript的成本。