优化 JavaScript 切换到 HTTP/2 异步和延迟 代码拆分 明智导入 节流和防抖 那又怎样

2025-06-10

优化 JavaScript

切换到 HTTP/2

异步与延迟

代码拆分

明智地进口

节流和去抖

所以呢

最近我有机会在NDC 悉尼发表关于网络性能的演讲,并获得了热烈的反响。

这启发了我针对那次演讲中涉及的每个主题撰写一系列帖子,谁知道呢,也许有一天这些帖子都会成为他们自己的演讲😃。

所有其他部分:

第 1 部分:HTML 和 CSS

第 2 部分使用 Preload/Prefetch 来提升加载时间

第 4 部分 图像优化

第五部分 Web 字体优化

是时候看看我们能为我们的老朋友 JavaScript 做些什么了。那就开始吧。

切换到 HTTP/2

随着越来越多的主机提供商支持HTTP/2,现在正是切换到该协议并受益于其多路复用特性的好时机。就性能而言,这意味着我们无需将所有 JavaScript 打包成大包来减少对服务器的调用次数。

HTTP/2旨在处理大量请求,因此您现在可以增加渲染页面所需的文件数量。但不要太多:

好事太多反而会变成坏事。

异步与延迟

正如我之前提到的,JavaScript 和 CSS 一样,都是渲染阻塞元素。这意味着浏览器需要等待 JavaScript 加载并执行完毕后才能解析HTML文档的其余部分。

这极大地增加了我们的“首次有意义的痛苦”。为了解决这个问题,我们可以使用两个很少人使用但非常有效的功能。

正常执行

当你使用<script>加载 JavaScript 文件时,它会中断文档的解析。浏览器会获取资源,执行此操作,然后继续解析:

正常执行

属性Async

Async属性用于指示此资源可以异步执行。解析不需要暂停,可以在资源从网络获取并准备就绪后立即执行。

<script async src="script.js">
Enter fullscreen mode Exit fullscreen mode

此属性只能用于外部 JavaScript 文件。该文件将并行下载,下载完成后,解析将暂停,以便执行脚本:

异步执行

属性Defer

Defer属性用于告诉浏览器在解析整个文档后执行此脚本。

<script defer src="script.js">
Enter fullscreen mode Exit fullscreen mode

就像Async这个文件被并行下载,但只有当整个文档被解析时才会执行HTML

延迟执行

最后请记住将所有script标签放在末尾,body以防止解析时出现更多延迟HTML

至于浏览器支持,幸运的是,所有主要浏览器都完全支持这些属性。

代码拆分

大多数现代网站都会将所有 JavaScript 捆绑在一起,从而增加加载时间并影响加载性能。

代码拆分允许你将应用程序代码拆分成单独的块,并在需要时进行延迟加载。这也意味着客户端所需的代码量最少,从而缩短了页面加载时间。

您可以将代码分为三个区域:

  • 供应商代码
  • 入口点
  • 动态分裂

供应商代码

Angular、React、moment 等供应商代码可以与主代码分离。Webpack完全支持此方法和其他方法。此技术让您能够更好地控制 bundles 的缓存失效无论应用程序或供应商代码是否独立更改。

这是每个应用程序都应该做的事情。

入口点

这种技术通过应用中的入口点来分离代码。像 webpack 这样的打包工具在构建应用的依赖关系树时,就是从这些入口点开始的。

这是迄今为止最简单的代码分割方法,但它是手动的并且存在一些缺陷:

  • 如果入口点之间有任何重复的模块,它们将被捆绑在两者中。
  • 它不够灵活,不能用于动态地拆分应用程序逻辑的代码。

当您有客户端路由或混合服务器端渲染和单页应用程序时,此技术不适用。

动态分裂

使用动态代码时,请单独编写代码import。这对于单页应用来说是最佳选择。例如,在 SPA 中为不同的路由设置不同的模块。

我是否真的需要代码分割?

这是我经常说“视情况而定”的其中一种(毕竟我是个顾问😉)。如果你的应用有很多功能独立的路由,并且大量使用了框架和库,那么答案很可能是“是”

但是,是否需要它取决于您对应用程序结构和代码的理解。

明智地进口

如果您使用npm或其他包管理系统来管理您的依赖项,那么您的 buid 文件夹中将会有很多额外的和不需要的文件。

当使用框架或库时,请确保调查它们是否有可以导入的单独模块,如果有,则只导入您需要的模块。

例如,假设你使用下划线,但只使用groupByshufflepartition。大多数人会像这样导入整个库:

import * as _ from 'underscore'
Enter fullscreen mode Exit fullscreen mode

除了这个之外,您还可以导入您需要的内容:

import {
  groupBy,
  shuffle,
  partition,
} from 'underscore'
Enter fullscreen mode Exit fullscreen mode

这样,您只需携带所需的内容,打包工具会帮您处理其余部分。您的整体软件包大小以及页面加载时间都会减少。

节流和去抖

好的,关于尺寸已经说得够多了,让我们看看还有什么地方可以提高我们的性能。

很多时候,你需要添加一个事件监听器来执行某些操作,比如监听页面滚动。然而,我们却忘记了监听器会在每次触发事件时触发。

window.addEventListener('scroll', function() {
  console.log('page scrolled')
})
Enter fullscreen mode Exit fullscreen mode

在上面的例子中,每当你滚动屏幕时,控制台都会打印出这条消息。想象一下,如果你在这个回调函数中有一些繁重的操作,这将会成为一个很大的性能瓶颈。

如果您无法删除该事件监听器并使用其他方法,那么您可以使用debouncethrottle来缓解这种情况。

去抖动

此功能强制函数调用在上次调用后经过一段时间后才会发生。例如,如果距离上次调用已过去 100 毫秒,则调用该函数。

从下划线来看这个实现:

const debounce = (func, delay) => {
  let inDebounce
  return function() {
    const context = this
    const args = arguments
    clearTimeout(inDebounce)
    inDebounce = setTimeout(
      () => func.apply(context, args),
      delay
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

现在我们可以每 100 毫秒对事件监听器进行一次去抖动:

var efficientScrollListener = debounce(
  function() {
    console.log('page scrolled')
  },
  100
)

window.addEventListener(
  'scroll',
  efficientScrollListener
)
Enter fullscreen mode Exit fullscreen mode

风门

节流与去抖动类似,但不同之处在于它会强制限制一段时间内函数的最大调用次数。例如,每 100 毫秒执行一次此函数。

以下是一个简单的实现:

const throttle = (func, limit) => {
  let inThrottle
  return function() {
    const args = arguments
    const context = this
    if (!inThrottle) {
      func.apply(context, args)
      inThrottle = true
      setTimeout(
        () => (inThrottle = false),
        limit
      )
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

现在我们可以限制滚动事件监听器:

var efficientScrollListener = throttle(
  function() {
    console.log('page scrolled')
  },
  100
)

window.addEventListener(
  'scroll',
  efficientScrollListener
)
Enter fullscreen mode Exit fullscreen mode

所以呢

我希望我已经提供了足够的信息,涵盖了在使用 JavaScript 时可以关注的一些方面,以提高应用程序的性能。如果您想了解其他主题,请在下方评论,我会在这里或其他文章中添加。

和往常一样,别忘了分享❤️。

鏂囩珷鏉ユ簮锛�https://dev.to/yashints/optimising-javascript-1f8b
PREV
页面可见性 API,让我们帮助用户节省电池寿命和数据😀
NEXT
了解剪贴板 API,更智能地与用户交互📋