宝哥软件园

基于JavaScript的性能优化技巧(分享)

编辑:宝哥软件园 来源:互联网 时间:2021-09-02

作为最常见的文字脚本语言,JavaScript在Web应用程序开发中得到了广泛的应用。为了提高Web应用的性能,从JavaScript的性能优化入手是一个不错的选择。

本文从加载、上下文、解析、编译、执行、绑定等方面讲解了JavaScript性能优化技巧,让更多的前端开发人员掌握这些知识。

什么是高性能JavaScript代码?

虽然目前还没有高性能代码的绝对定义,但是有一个以用户为中心的性能模型,可以作为参考:RAIL模型。

作出反应

如果你的应用程序能够在100毫秒内响应用户的操作,用户会认为响应是即时的。这适用于可点击的元素,而不是滚动或拖动操作。

动画

在60Hz的显示器上,我们想要每秒60帧的动画和滚动,在这种情况下,每帧大约是16ms,在这16 ms的时间里,实际上只需要8-10ms就可以完成所有的工作,剩下的时间都被浏览器的内部和其他差异所占据。

无功

如果你有一个任务需要很长时间,需要连续运行,请确保把它分成小块,让主线程响应用户的输入操作。不应有任务延迟超过50毫秒的用户输入。

负荷

页面加载应在1000毫秒内完成。在移动设备上,这是一个困难的目标,因为它涉及到页面的交互,而不仅仅是屏幕上的渲染和滚动。

现代加载最佳实践(2017年Chrome开发峰会)

如果移动网站加载时间超过三秒,53%的用户会放弃访问

50%的用户希望在2秒内完成页面加载

77%的移动网站加载3G网络需要10秒以上

19秒是3G网络上移动台的平均加载时间

代码内容

你可能已经注意到了,最大的瓶颈是加载网站所需的时间。具体来说,就是JavaScript的下载、解析、编译和执行时间。除了加载更少的JavaScript文件或更灵活地加载它们,似乎没有其他方法。

除了启动网站,JavaScript代码实际上是如何工作的?

在优化代码之前,请考虑您当前正在构建的内容。你是在建造一个框架还是一个VDOM图书馆?您的代码需要每秒执行数千个操作吗?您是否正在制作一个具有严格时间要求的库来处理用户输入和/或动画?如果没有,你需要把时间和精力转移到更有影响力的地方。

编写高性能代码并不那么重要,因为它通常对宏观计划影响不大。50k ops/s听起来比1k ops/s好,但总体时间在大多数情况下不会改变。

解析、编译和执行

从根本上说,大多数JavaScript的性能问题不在于运行代码本身,而在于在代码开始执行之前必须采取的一系列步骤。

我们在这里讨论抽象层面。大多数运行在计算机上的代码都是编译后的二进制格式。这意味着,除了操作系统级别的所有抽象之外,代码可以在硬件上本地运行,无需准备。

JavaScript代码不是预编译的,它在浏览器上是可读的。

JavaScript代码首先会被解析,即读取并转换成可用于编译的计算机索引的结构,然后编译成字节码,最后编译成机器代码供设备/浏览器执行。

另一个非常重要的方面是,JavaScript是单线程的,运行在浏览器的主线程上。这意味着一次只能运行一个进程。如果您的开发工具性能时间线充满黄色峰值,并且CPU利用率达到100%,将会出现帧丢失。这是一种常见且恼人的滚动操作情况。

所有这些解析、编译和执行任务都需要在JavaScript代码运行之前完成。在ChromeV8引擎中,解析和编译约占总JavaScript执行时间的50%。

所以在这一部分,我们应该知道两件事:

1.虽然JavaScript解析时间的长短和数据包的大小并不是完全线性的,但是需要处理的JavaScript越少,花费的时间就越少。

2.你使用的每一个JavaScript框架(React,Vue,Angular,Preact.)是另一个抽象层次(除非是预编译层次)。这不仅会增加包的大小,还会降低代码的速度,因为您不会直接与浏览器通信。

有一些方法可以缓解这种情况,例如使用服务工作人员在后台的另一个线程中执行一些工作,或者使用asm.js编写代码,使编译机器指令变得更加容易。

我们能做的就是避免使用JavaScript动画库。只有在完全不可能使用常规的CSS变换和动画时,才使用这些库。

即使这些JavaScript动画库使用CSS转换、复合属性和requestAnimationFrame(),它们仍然在JavaScript的主线程上运行。基本上,这些库每16毫秒使用内联样式访问一次DOM。你需要确保所有的JavaScript在每帧8毫秒内完成,以保持动画流畅。

另一方面,CSS动画和转换将在主线程中运行。如果能够高效执行,可以避免重新布局/重排。

考虑到大多数动画在加载或用户交互期间运行,这可以为您的web应用程序提供一个非常重要的调整空间。

网络动画应用编程接口是一个即将推出的功能集,它可以在没有主线程的情况下执行高性能的JavaScript动画。但就目前而言,有必要继续使用CSS转换等技术。

束的大小非常重要

不再是/body结束标记前有多个脚本的时代。现在,在npm上可以找到各种工具包,这些工具包和Webpack可以捆绑成一个1MB大小的单一JavaScript文件,在完成数据计划时提醒用户的浏览器进行抓取。

这允许您使用更少的JavaScript,这意味着您的项目可能不再需要整个Lodash库。如果非要用JavaScript库,也可以考虑用React或者HyperHTML以外的东西,只有React的1/20大小。

Webpack 3有神奇的功能,叫做代码分段和动态导入。它没有将所有的JavaScript模块捆绑到一个app.js包中,而是使用import()语法自动拆分代码并异步加载。

您可以在不使用框架、组件和客户端路由的情况下获得这些好处。您只需在主JavaScript文件中编写以下内容:

if (document.querySelector(')。mega-widget’){ import('。/mega-widget’);}如果您的应用程序需要在页面上使用此小部件,它将动态加载所需的支持代码。

此外,Webpack需要运行时来工作,并将其注入所有。它生成的js文件。如果使用commonChunks插件,可以使用以下方法将运行时提取到Chunk中:

new Webpack . optimize.commonchunkplugin({ name : ' runtime ',}),以确保在主JavaScript包之前已经加载了Webpack,然后所有其他区块中的运行时将被剥离到它们自己的文件中,这也称为runtime.js例如:

脚本src=' http:runtime.js '脚本src=' http3360main-bundle.js '然后是编译代码和polyfills的部分。如果您正在编写现代JavaScript代码(ES6),可以使用Babel将其转换为与ES5兼容的代码。与原生ES6代码相比,编译不仅增加了文件大小,而且增加了复杂性,性能往往会下降。

此外,您可能会使用babel-polyfill软件包和whatwg-fetch来修复旧浏览器中缺失的功能。因此,如果您正在编写async/await,您需要使用包再生器-运行时的生成器来编译。

问题是你在JavaScript包中添加了将近100KB的内容,这不仅是一个巨大的文件,还预示着巨大的解析和执行成本,这样才能支持旧版本的浏览器。

一种方法是创建两个独立的包,并根据实际情况加载它们。在babel-preset-env的帮助下,babel转换编译器将更容易处理面对新旧浏览器的情况。

一种不标准但有效的方法是将以下内容放入内联脚本中:

(function() {尝试{ new Function(' async()={ } '))();} catch(错误){ //创建指向legacy-bundle.js的脚本标记;返回;} //创建指向modern-bundle.js的脚本标记;})();如果浏览器不识别异步功能,它将被视为浏览器的旧版本,并将使用polyfill包。如果能够识别,用户就会被现代浏览器处理。

结论

为了提高网站的运行速度,需要保证网站能够快速加载JavaScript文件,实现快速交互。您的JavaScript代码应该被分成更小的、可管理的包,并尽可能异步加载。在服务器端,请确保启用HTTP 2.0,以实现更快的并行传输和gzip/Brotli压缩,从而大大减少JavaScript的传输大小。

以上基于JavaScript性能优化技巧的经验(分享)是边肖与大家分享的全部内容,希望能给大家一个参考和支持。

更多资讯
游戏推荐
更多+