JavaScript performance optimization skills sharing

As the most common literal translation scripting language, JavaScript has been widely used in Web application development. In order to improve the performance of Web applications, starting from the direction of JavaScript performance optimization will be a good choice.

This article explains JavaScript performance optimization techniques from the aspects of loading, context, parsing, compilation, execution, and bundling, so that more front-end developers can master this knowledge.

 

What is high performance JavaScript code?

Although there is currently no absolute definition of high-performance code, there is a user-centric performance model that can be used as a reference: the RAIL model .

  • response

If your application can respond to a user's action within 100 milliseconds, the user will consider the response immediate. This works for clickable elements, not for scrolling or dragging operations.

  • animation

On a 60Hz monitor, we would expect 60 frames per second for animations and scrolling, which is about 16ms per frame in this case. During that 16ms period, there's really only 8-10ms to do all the work, the rest is taken up by browser internals and other differences.

  • free work

If you have a long-running task that needs to run continuously, make sure to break it into small chunks to allow the main thread to react to user input. There should not be a user input with a task delay of more than 50ms.

  • load

The page load should complete within 1000ms. On mobile devices, this is a difficult goal to achieve because it involves interacting with the page, not just rendering and scrolling on the screen.

 

Modern Loading Best Practices (Chrome Dev Summit 2017)

 Let's take a look at some statistics :

  • 53% of users abandon a mobile site if it takes more than three seconds to load
  • 50% of users expect a page to load in less than 2 seconds
  • 77% of mobile sites take more than 10 seconds to load on a 3G network
  • 19 seconds is the average load time for a mobile site on a 3G network

 

code content

As you may have noticed, the biggest bottleneck is the time it takes to load a website. Specifically, JavaScript download, parsing, compilation, and execution times. There seems to be no other way than to load fewer JavaScript files or to load more flexibly.

除去启动网站之外,JavaScript 代码又是如何实际工作的呢?

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

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

 

解析、编译和执行

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

我们在这里讨论抽象层次的问题。计算机上运行的大多数代码都是编译后的二进制格式。意思是说,除了所有的操作系​​统级别的抽象外,代码都可以在硬件上本地运行,不需要准备工作。

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

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

另一个非常重要的方面是:JavaScript 是单线程的,并且在浏览器的主线程上运行。这意味着一次只能运行一个进程。如果你的 DevTools 性能时间线充满黄色峰值,同时 CPU 占用率达到100%,则将出现丢帧的情况。这是滚动操作常出现的,也是很讨厌的一种情况。

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

所以在这部分中,应该了解两件事情:

1. 虽然 JavaScript 解析的时间长度和包的大小不是完全线性的,但是需要处理的 JavaScript 越少,则所花时间越少。

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

 

有些方法可以缓解这种情况,比如使用 service workers 在后台的另一个线程中执行部分工作,或者使用 asm.js 编写更容易编译机器指令的代码。

我们所能做的,就是避免使用 JavaScript 动画库。只有在使用常规的 CSS 转换和动画完全无法实现时,才去使用这些库。

即使这些 JavaScript 动画库使用 CSS 转换,合成属性和 requestAnimationFrame( ),但是它们仍然运行在 JavaScript 的主线程上。基本上这些库会使用内联样式每16ms访问一次 DOM。你需要确保所有的 JavaScript 都在每帧8ms以内完成,才能保持动画的平滑性。

另一方面,CSS 动画和转换会在主线程中运行,如果能够高效执行,则能避免重新布局/重排的情况出现。

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

web Animations API 是一个即将到来的功能集,它能够脱离主线程执行高性能的 JavaScript 动画。但就目前而言,还需要继续使用 CSS 转换等技术。

 

捆绑尺寸非常重要

现在已经不再是在 </body> 结束标签之前包含有多个 <script> 的时代了。现在,可以在 npm 上找到各式各样的工具包,并且可以将这些工具包和 Webpack 捆绑在一个单个的 1MB 大小的 JavaScript 文件中,在完成数据计划时,提醒用户的浏览器进行爬取。

这样可以使用更少量的 JavaScript,这也意味着你的项目可能不再需要整个Lodash库。如果必须使用 JavaScript 库,也可以考虑使用 React 以外的东西,比如 Preact 或者 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.CommonsChunkPlugin({
  name: 'runtime',
}),

确保 Webpack 在主 JavaScript 包之前已完成加载,那么所有其它 chunk 中的运行时间会剥离到各自的文件中,这种情况也被成为 runtime.js。例如:

<script src="runtime.js">
<script src="main-bundle.js">

然后是编译代码和 polyfills 的部分。如果你正在编写现代 JavaScript 代码(ES6 +),则可以使用 Babel 将其转换为 ES5 兼容的代码。与原生 ES6+ 代码相比,编译不仅增加了文件的大小,还增加了复杂性,并且经常会出现性能下降的情况。

除此之外,你还很可能使用 babel-polyfill 软件包和 whatwg-fetch,来修复旧版本浏览器中的缺失功能。因此如果你正在编写 async/await,你还需要使用包 regenerator-runtime 的生成器来进行编译。

问题是,你为 JavaScript 软件包添加了近 100KB 的内容,这不仅是一个巨大的文件,而且预示着巨大的解析和执行花费,以便能够支持旧版本的浏览器。

一种方法是创建两个独立的 bundle,并根据实际条件来加载它们。Babel 转换编译器在 babel-preset-env 的帮助下,会使同时面临新旧两种浏览器的情况更加容易处理。

一个并不规范但行之有效的方法,是将以下内容放在一个内联脚本中:

(function() {
  try {
    new Function('async () => {}')();
  } catch (error) {
    // create script tag pointing to legacy-bundle.js;
    return;
  }
  // create script tag pointing to modern-bundle.js;;
})();

如果浏览器无法识别 async 函数,则会被认为是旧版本的浏览器,此时就会用到 polyfill 包。如果能识别,用户则将得到现代浏览器的处理。

 

 

JavaScript 开发工具推荐

SpreadJS 纯前端表格控件是基于 HTML5 的 JavaScript 电子表格和网格功能控件,提供了完备的公式引擎、排序、过滤、输入控件、数据可视化、Excel 导入/导出等功能,适用于 .NET、Java 和移动端等各平台在线编辑类 Excel 功能的表格程序开发。

 

结论

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

原文链接:https://www.sitepoint.com/javascript-performance-optimization-tips-an-overview/

转载请注明出自:葡萄城控件

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326234771&siteId=291194637