async-components

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Async Components

异步组件

Table of Contents

目录

When developing large web applications, performance is paramount. The speed with which a page loads and the responsiveness of its interactive elements can greatly impact user experience. As web applications grow in size and complexity, it can become important to ensure that large bundles of code are loaded only when needed. Enter asynchronous components in Vue.
Components are the fundamental building blocks for constructing the UI. Typically, when we use components, they're automatically loaded and parsed, even if they aren't immediately needed.
开发大型Web应用时,性能至关重要。页面加载速度和交互元素的响应能力会极大影响用户体验。随着Web应用规模和复杂度不断提升,确保大型代码包仅在需要时加载变得尤为重要。Vue的异步组件正是为此而生。
组件是构建UI的基本单元。通常情况下,我们使用组件时,即使它们并非立即需要,也会被自动加载和解析。

When to Use

适用场景

  • Use this when components have large bundle sizes and aren't needed on initial page load
  • This is helpful for modals, dialogs, or any UI that is conditionally rendered based on user action
  • 适用于代码包体积较大、初始页面加载时不需要的组件
  • 对模态框、对话框或任何基于用户操作条件渲染的UI非常有帮助

When NOT to Use

不适用场景

  • For small components where the async loading overhead (chunk request, parsing) outweighs the bundle savings
  • For components that are always visible on initial render — async loading delays their appearance
  • When the component is already part of the main chunk and splitting it out wouldn't meaningfully reduce bundle size
  • 小型组件:异步加载的开销(分片请求、解析)超过代码包体积减少带来的收益
  • 初始渲染时始终可见的组件:异步加载会延迟其展示
  • 已属于主代码分片的组件:拆分出去无法有效减小代码包体积

Instructions

操作步骤

  • Use
    defineAsyncComponent()
    with dynamic
    import()
    to load components on demand
  • Provide
    loadingComponent
    and
    errorComponent
    options for better user experience
  • Combine with
    v-if
    to trigger async loading only when the component is actually needed
  • Use the
    delay
    and
    timeout
    options for fine-grained control over loading behavior
  • 使用
    defineAsyncComponent()
    配合动态
    import()
    实现组件按需加载
  • 配置
    loadingComponent
    errorComponent
    选项以提升用户体验
  • 结合
    v-if
    仅在组件实际需要时触发异步加载
  • 使用
    delay
    timeout
    选项对加载行为进行精细化控制

Details

详细说明

Asynchronous components, on the other hand, allow us to define components in a way that they're loaded and parsed only when they're required or when certain conditions are met.
Assume we had a simple modal component that becomes rendered when a button is clicked from the parent. The
Modal.vue
component file will only contain template and styles that dictate how the modal appears.
html
<template>
  <div class="modal-mask">
    <div class="modal-container">
      <div class="modal-body">
        <h3>This is the modal!</h3>
      </div>

      <div class="modal-footer">
        <button class="modal-default-button" @click="$emit('close')">OK</button>
      </div>
    </div>
  </div>
</template>
In the parent
App
component, we can render the modal component and a button that when clicked toggles the visibility of the modal component with the help of a reactive boolean value (
showModal
).
html
<template>
  <button id="show-modal" @click="showModal = true">Show Modal</button>
  <Modal v-if="showModal" :show="showModal" @close="showModal = false" />
</template>

<script setup>
  import { ref } from "vue";
  import Modal from "./components/Modal.vue";

  const showModal = ref(false);
</script>
From this example, we can see that the modal component is shown only under a specific circumstance — when the user clicks the
Show Modal
button. Despite this, the JavaScript bundle associated with the component is loaded automatically when the entire webpage is loaded even before the modal is made visible.
This is fine for the majority of cases. However, under conditions where the bundle size of the modal is really large and/or the application has a multitude of such components, this can lead to a delayed initial load time. With every added bundle, even if it's related to components that are rarely used, the time it takes for the initial page to load grows.
而异步组件允许我们以一种“仅在需要或满足特定条件时才加载和解析”的方式定义组件。
假设我们有一个简单的模态框组件,当用户点击父组件中的按钮时才会渲染。
Modal.vue
组件文件仅包含控制模态框外观的模板和样式。
html
<template>
  <div class="modal-mask">
    <div class="modal-container">
      <div class="modal-body">
        <h3>This is the modal!</h3>
      </div>

      <div class="modal-footer">
        <button class="modal-default-button" @click="$emit('close')">OK</button>
      </div>
    </div>
  </div>
</template>
在父组件
App
中,我们可以渲染模态框组件,并通过一个响应式布尔值(
showModal
)控制按钮点击时模态框的显示状态。
html
<template>
  <button id="show-modal" @click="showModal = true">Show Modal</button>
  <Modal v-if="showModal" :show="showModal" @close="showModal = false" />
</template>

<script setup>
  import { ref } from "vue";
  import Modal from "./components/Modal.vue";

  const showModal = ref(false);
</script>
从这个例子可以看出,模态框组件仅在特定情况下才会显示——当用户点击“Show Modal”按钮时。尽管如此,该组件对应的JavaScript代码包会在整个网页加载时自动加载,甚至早于模态框被展示的时间。
在大多数情况下这没问题,但如果模态框的代码包体积非常大,或者应用中有大量此类组件,就会导致初始加载延迟。每增加一个代码包,即使它关联的组件很少被使用,初始页面加载时间也会增加。

defineAsyncComponent

defineAsyncComponent

This is where Vue allows us to divide an app into smaller chunks by loading components asynchronously with the help of the
defineAsyncComponent()
function.
js
import { defineAsyncComponent } from "vue";

const AsyncComp = defineAsyncComponent(() => {
  return new Promise((resolve, reject) => {
    // ...load component from the server
    resolve(/* loaded component */);
  });
});
The
defineAsyncComponent()
function accepts a loader function that returns a Promise that resolves to the imported component. However, instead of defining our async component function like the above, we can leverage dynamic imports to load an ECMAScript module asynchronously.
js
import { defineAsyncComponent } from "vue";

export const AsyncComp = defineAsyncComponent(() =>
  import("./components/MyComponent.vue")
);
Let's see this in action for our modal example. We'll create a new file titled
AsyncModal.js
:
js
import { defineAsyncComponent } from "vue";

export const AsyncModal = defineAsyncComponent(() => import("./Modal.vue"));
In our parent
App
component, we'll now import and use the
AsyncModal
asynchronous component in place of the
Modal
component.
html
<template>
  <button id="show-modal" @click="showModal = true">Show Modal</button>
  <AsyncModal v-if="showModal" :show="showModal" @close="showModal = false" />
</template>

<script setup>
  import { ref } from "vue";
  import { AsyncModal } from "./components/AsyncModal";

  const showModal = ref(false);
</script>
With this small change, our modal component will now be asynchronously loaded! When our application webpage initially loads, the bundle for the
Modal
component is no longer loaded automatically upon page load. When we click the button to trigger the modal to be shown, the bundle is then asynchronously loaded as the modal component is being rendered.
Vue提供了
defineAsyncComponent()
函数,允许我们通过异步加载组件将应用拆分为更小的代码分片。
js
import { defineAsyncComponent } from "vue";

const AsyncComp = defineAsyncComponent(() => {
  return new Promise((resolve, reject) => {
    // ...从服务器加载组件
    resolve(/* loaded component */);
  });
});
defineAsyncComponent()
函数接受一个加载器函数,该函数返回一个Promise,Promise会解析为导入的组件。不过,我们无需像上面那样定义异步组件函数,而是可以利用动态import来异步加载ECMAScript模块。
js
import { defineAsyncComponent } from "vue";

export const AsyncComp = defineAsyncComponent(() =>
  import("./components/MyComponent.vue")
);
让我们在模态框示例中实践这一用法。创建一个新文件
AsyncModal.js
js
import { defineAsyncComponent } from "vue";

export const AsyncModal = defineAsyncComponent(() => import("./Modal.vue"));
在父组件
App
中,我们现在导入并使用
AsyncModal
异步组件来替代原来的
Modal
组件。
html
<template>
  <button id="show-modal" @click="showModal = true">Show Modal</button>
  <AsyncModal v-if="showModal" :show="showModal" @close="showModal = false" />
</template>

<script setup>
  import { ref } from "vue";
  import { AsyncModal } from "./components/AsyncModal";

  const showModal = ref(false);
</script>
只需这一小改动,我们的模态框组件就可以异步加载了!当应用网页初始加载时,
Modal
组件的代码包不再随页面自动加载。当我们点击按钮触发模态框显示时,代码包才会在组件渲染时被异步加载。

Loading and error UI

加载与错误状态UI

With
defineAsyncComponent()
, Vue provides developers with more than just a means of asynchronously loading components. It also offers capabilities to display feedback to users during the loading process and handle any potential errors.
除了异步加载组件,
defineAsyncComponent()
还为开发者提供了在加载过程中向用户展示反馈、处理潜在错误的能力。

loadingComponent

loadingComponent

There may be times we may want to provide visual feedback to users while a component is being fetched. To achieve this,
defineAsyncComponent()
has a
loadingComponent
option that lets us specify a component to show during the loading phase.
js
import { defineAsyncComponent } from "vue";
import Loading from "./Loading.vue";

export const AsyncModal = defineAsyncComponent({
  loader: () => import("./Modal.vue"),
  loadingComponent: Loading,
});
As the modal component becomes asynchronously loaded, the user will now be presented with a
Loading...
message.
有时我们希望在组件加载过程中向用户提供视觉反馈。为此,
defineAsyncComponent()
提供了
loadingComponent
选项,允许我们指定加载阶段显示的组件。
js
import { defineAsyncComponent } from "vue";
import Loading from "./Loading.vue";

export const AsyncModal = defineAsyncComponent({
  loader: () => import("./Modal.vue"),
  loadingComponent: Loading,
});
当模态框组件异步加载时,用户将看到“Loading...”提示信息。

errorComponent

errorComponent

In certain conditions (e.g. poor internet connections), there may be chances that the asynchronous component fails to load. The
defineAsyncComponent()
function offers the
errorComponent
option to handle such situations, allowing us to specify a component to be displayed when there's a loading error.
js
import { defineAsyncComponent } from "vue";
import Loading from "./Loading.vue";
import Error from "./Error.vue";

export const AsyncModal = defineAsyncComponent({
  loader: () => import("./Modal.vue"),
  loadingComponent: Loading,
  errorComponent: Error,
});
When the modal component fails to load, the
Error
component template will be shown.
The
defineAsyncComponent()
function accepts further options like
delay
,
timeout
,
suspensible
, and
onError()
which provide developers with more granular control over the asynchronous loading behavior and user experience. Be sure to check out the API documentation for more details on these properties.
The
defineAsyncComponent()
function can help in breaking down the initial load of a Vue application into manageable chunks by deferring the loading of certain components until they're needed. This can help improve page load times and overall application performance especially when an application has numerous components that have a large bundle size.
在某些情况下(例如网络连接不佳),异步组件可能加载失败。
defineAsyncComponent()
函数提供了
errorComponent
选项来处理此类情况,允许我们指定加载错误时显示的组件。
js
import { defineAsyncComponent } from "vue";
import Loading from "./Loading.vue";
import Error from "./Error.vue";

export const AsyncModal = defineAsyncComponent({
  loader: () => import("./Modal.vue"),
  loadingComponent: Loading,
  errorComponent: Error,
});
当模态框组件加载失败时,将显示
Error
组件的模板内容。
defineAsyncComponent()
还支持
delay
timeout
suspensible
onError()
等更多选项,为开发者提供对异步加载行为和用户体验更精细的控制。如需了解这些属性的详细信息,请查看API文档
defineAsyncComponent()
函数可以通过延迟加载某些组件直到需要时再加载,将Vue应用的初始加载拆分为可管理的代码分片。当应用包含大量体积较大的组件时,这有助于缩短页面加载时间并提升整体应用性能。

Source

来源

References

参考资料