跳到正文

Vue 生命周期与 nextTick ​

  • 状态:未准备
  • 适用方向:前端 / Go 全栈
  • 最近复习:待填写
  • 下次复习:待安排

一句话回答 ​

生命周期把逻辑放到挂载、更新、卸载等阶段;nextTick 等待 Vue 当前待处理的 DOM 更新完成,KeepAlive 停用不等于卸载,资源应按真实生命周期释放或暂停。

原理解释 ​

常用 Hook ​

  • onBeforeMount / onMounted:初次 DOM 挂载前后。onMounted 不保证所有异步子组件和 Suspense 子树都已完成,也不在服务端渲染时运行。
  • onBeforeUpdate / onUpdated:响应式更新造成 DOM 改动前后;避免在 onUpdated 无条件修改依赖导致循环。
  • onBeforeUnmount / onUnmounted:实例卸载前后;清理计时器、原生监听、连接和媒体等外部资源。
  • onActivated / onDeactivated:KeepAlive 缓存子树的激活/停用,可控制可见时才需要的工作。
vue
<script setup lang="ts">
import { ref, nextTick, onMounted, onUnmounted } from 'vue'

const count = ref(0)
const label = ref<HTMLElement | null>(null)
async function add() {
  count.value++
  await nextTick()
  console.log(label.value?.textContent)
}
function onResize() { console.log(window.innerWidth) }
onMounted(() => window.addEventListener('resize', onResize))
onUnmounted(() => window.removeEventListener('resize', onResize))
</script>

<template>
  <button @click="add">增加</button>
  <span ref="label">{{ count }}</span>
</template>

count.value 同步变化,但 DOM 更新被批处理;先修改,再 nextTick 才能等待该轮更新。nextTick 不等待任意网络请求,也不承诺屏幕已经绘制。

场景与边界 ​

生命周期 Hook 通常需在 setup 同步阶段注册,以关联当前组件;不要在任意 setTimeout 中才注册。setup 同步创建的侦听器会随组件卸载停止,但异步回调里另行创建的侦听器可能需要手动停止。

KeepAlive 缓存实例和状态,include/exclude 按组件名过滤,max 限制缓存数量并采用 LRU 淘汰。停用不会自动保证所有业务订阅和定时器暂停,应按业务在激活/停用 Hook 中处理,最终卸载仍需兜底释放。

项目中的应用 ​

当前无 Vue 实现。对照 SimulSpeak 媒体生命周期 练习设计 Vue 会话组件,特别验证“授权未结束就卸载”和“KeepAlive 隐藏后是否继续采集”。生命周期名不能替代晚到资源检查。

常见追问 ​

  • 父子 mounted 顺序? 同步子组件通常先 mounted,再父组件;不能把这个顺序扩展到所有异步组件。
  • setTimeout 0 能替代 nextTick 吗? 不应依赖它偶然排在更新之后,nextTick 明确关联 Vue 更新队列。
  • 模板 ref 何时可用? 挂载后才可靠取得,条件卸载后可变回 null;使用前需处理空值。

参考资料 ​

理解机制,讲清取舍,用复盘检验掌握。