在构建现代 Web 应用程序时,
诸如 Webpack 或 Rollup 之类的打包器会获取应用程序的源代码,并将其捆绑到一个或多个包中。
当用户访问网站时,会请求并加载包,以便将数据显示到用户的屏幕上。
JavaScript 引擎(如 V8)能够解析和编译用户在加载时请求的数据。
尽管现代浏览器已经发展为尽可能快速和高效地解析和编译代码,但开发人员仍然负责优化该过程中的两个步骤:
-
请求数据的加载时间和执行时间。
-
确保尽可能缩短执行时间以防止阻塞主线程。
尽管现代浏览器能够在包到达时对其进行流式传输,但在用户设备上绘制第一个像素之前仍然需要很长时间。
捆绑包越大,引擎到达第一次渲染调用所在的行所需的时间就越长。
在那之前,用户必须盯着空白屏幕很长一段时间,这可能……非常令人沮丧!
我们希望尽快向用户显示数据。
更大的包会导致加载时间、处理时间和执行时间增加。
如果可以减少这个包的大小,以加快速度,那就太好了。
可以将捆绑包拆分为多个较小的捆绑包,而不是请求一个包含不必要代码的巨大捆绑包!
通过对应用程序进行捆绑拆分,
可以减少加载、处理和执行捆绑所需的时间!
通过减少加载和执行时间,可以减少在用户屏幕上绘制第一个内容之前所花费的时间,
即 First Contentful Paint
,以及将最大组件渲染到屏幕之前所花费的时间,即 Largest
内容丰富的油漆。
虽然能够在屏幕上看到数据很棒,但不只是想看到内容。
为了拥有一个功能齐全的应用程序,希望用户也能够与之交互!
用户界面只有在包被加载和执行后才变得交互。 将所有内容绘制到屏幕上并进行交互之前所需的时间称为交互时间。
更大的包并不一定意味着更长的执行时间。
有可能我们加载了大量用户甚至不会使用的代码! 也许捆绑包的某些部分只会在特定的用户交互中执行,用户可能会也可能不会这样做!
在用户能够在屏幕上看到任何内容之前,引擎仍然必须加载、解析和编译在初始渲染中甚至没有使用的代码。
尽管由于浏览器处理这两个步骤的高效方式,解析和编译成本实际上可以被忽略,但获取比必要更大的包可能会损害应用程序的性能。
低端设备或速度较慢的网络上的用户会在获取捆绑包之前看到加载时间显着增加。
第一部分仍然需要加载和处理,即使引擎只使用文件的最后一部分以便我们可以将这些代码与呈现初始页面所需的代码分开,
而不是最初请求在当前导航中没有高优先级的部分代码。
通过将大包拆分成两个较小的包,main.bundle.js
和 emoji-picker.bundle.js
,通过获取更少量的数据来减少初始加载时间。
在这个章节中,介绍了一些方法,这些方法允许将应用程序捆绑拆分成多个较小的捆绑包,并以最有效和性能最好的方式加载资源。