Suspense组件

时间:2022-12-18 18:10:07

先上官网:https://cn.vuejs.org/guide/built-ins/suspense.html 

注意一下 
<Suspense> 是一项实验性功能。它不一定会最终成为稳定功能,并且在稳定之前相关 API 也可能会发生变化。

在使用了之后在浏览器控制台会有如下打印,至少目前是

Suspense组件 

<Suspense> 是一个内置组件,用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态。 

就说Suspense可以直接使用的。基本使用如下: 

<Suspense>
  <template #default>
    <myComp />
  </template>
  <template #fallback>
    <h3>加载中.....</h3>
  </template>
</Suspense>

在等待异步依赖组件的时候,会先展示加载中..... 

<Suspense> 可以等待的异步依赖有两种: 

  • 带有异步 setup() 钩子的组件。这也包含了使用 <script setup> 时有顶层 await 表达式的组件。

  • 异步组件

首先看第一种,带有异步setup钩子的组件 

先看父组件: 

<template>
  <div class="main">
    <Suspense>
      <template #default>
        <A />
      </template>
      <template #fallback>
        <h3>加载中.....</h3>
      </template>
    </Suspense>
  </div>
</template>
<script setup lang="ts">
import A from "./A.vue";
</script>
<style scoped>
.main {
  width: 100%;
  height: 100%;
}
</style>

再看下子组件A.vue 

<template>
  <div class="A">
    <div>{{ user.name || '' }}</div>
    <div>{{ user.age || '' }}</div>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue'

type Info = { name: string, age: number }
let user = ref<Info>()

function getUser(flag:Boolean = true) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if(flag) {
        resolve({ name: 'wft', age: 18 })
      } else {
        reject('错错错')
      }
    }, 2000)
  })
}

try {
  user.value = await getUser(true) as Info
} catch(e) {}

</script>
<style scoped>
.A {
  width: 200px;
  height: 200px;
  margin: 20px 0 0 20px;
  border: 1px solid red;
  display: flex;
  justify-content: center;
  align-items: center;
}
.A div {
  font-size: 20px;
  color: red;
}
</style>

效果  

 Suspense组件

就是当我们的A组件中的异步操作未完成的时候,A组件是不会加载的

第二种就是 异步组件 

异步组件默认就是“suspensible”的。这意味着如果组件关系链上有一个 <Suspense>,那么这个异步组件就会被当作这个 <Suspense> 的一个异步依赖。在这种情况下,加载状态是由 <Suspense> 控制,而该组件自己的加载、报错、延时和超时等选项都将被忽略。

异步组件也可以通过在选项中指定 suspensible: false 表明不用 Suspense 控制,并让组件始终自己控制其加载状态。

官方:异步组件 

const B = defineAsyncComponent(() => import('./B.vue'))
const B = defineAsyncComponent(() => {
  return new Promise((resolve, reject) => {
    // ...从服务器获取组件
    resolve(/* 获取到的组件 */)
  })
})
const B = defineAsyncComponent({
  // 加载函数
  loader: () => import('./B.vue'),
  // 加载异步组件时使用的组件
  loadingComponent: LoadingComponent,
  // 展示加载组件前的延迟时间,默认为 200ms
  delay: 200,
  // 加载失败后展示的组件
  errorComponent: ErrorComponent,
  // 如果提供了一个 timeout 时间限制,并超时了
  // 也会显示这里配置的报错组件,默认值是:Infinity
  timeout: 3000
})

也是可以搭配Suspense使用的 

这里注意,我们使用defineAsyncComponent 使用异步组件、动态导入的时候,那么该组件在首屏的时候是不会加载该资源的,等我们真正用到的时候才会去加载,所以这也是一种首屏优化的方案。案例就像我们使用tabs标签页的时候,每个页签可以单独封装成自己的组件、写自己的逻辑,当点击到某个tab页签的时候再去加载对应的资源,这个时候组件就可以使用defineAsyncComponent动态导入组件