前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库Vue effectScope 嵌套 父停止 子作用域
VuVue侦听与生命周期

Vue 嵌套 effectScope 在父级停止时会怎样?

默认嵌套把生命周期组成一棵树:结束一条父分支时,它的后代也应该结束。

前端进阶之旅 · 一题精讲更新于 2026.09.06
Vue#侦听与生命周期
先看核心答案读代码示例
理解线索

用树形所有权理解停止方向

  1. 父到子父级 stop 沿默认作用域树清理所有后代
  2. 子到父子级 stop 只结束自己的分支
  3. 分离节点detached 不挂入父树,必须单独收尾

作用域树表达资源所有权,不等同于组件渲染树,两者有时重合但不是同一结构。

核心回答

先记住这个答案

在活动父 scope 的 run 中创建普通 effectScope,子 scope 会被父级收集。调用父级 stop 时,父级效果、默认子 scope 及更深后代会一起停止。子 scope 可以先独立 stop,而不影响父级其他效果;反向则会级联。effectScope(true) 是明确的例外,它不加入父树,需要自行停止。嵌套只管理创建时的作用域关系,不会自动捕获异步回调稍后创建的效果。

  • 默认子作用域随父级级联停止
  • 子级可提前结束而不停止父级
  • detached 子级不参与默认级联

嵌套关系在创建时建立

只有创建子 scope 时父 scope 正处于 run 的活动执行中,默认子级才会登记到这个父级。把 scope 变量放在嵌套函数里,或在文件层级上看起来属于某模块,都不是运行时归属依据。

组合式函数内部创建 scope 时,调用该函数的当前活动作用域会影响所有权。可复用库应在文档中说明它依赖当前 scope,或由调用方显式传入 owner,避免同一函数在不同调用位置呈现意外寿命。

分别观察子级提前停止和父级停止

下例父级与子级各建立一个 watchEffect。先停止子级并改变 source,只增加父级记录;随后停止父级再改变,两份记录都保持不变,说明停止方向由所有权树决定。

这个实验使用默认子 scope。若将 child 改为 effectScope(true),父级停止后它仍会响应,必须额外 child.stop;因此评审代码时要注意那个看似很小的 true 参数。

子级提前结束不影响父级TypeScript
import { effectScope, ref, watchEffect } from 'vue'

const source = ref(0)
const parentSeen: number[] = []
const childSeen: number[] = []
const parent = effectScope()
let child!: ReturnType<typeof effectScope>
parent.run(() => {
  watchEffect(() => parentSeen.push(source.value))
  child = effectScope()
  child.run(() => watchEffect(() => childSeen.push(source.value)))
})

初始两边都记录零。child.stop 后改为一并等待,只有 parentSeen 增加;parent.stop 后改为二并等待,两边都不再增加。这样同时验证两个停止方向。

按功能边界而非文件层级嵌套

例如编辑器工作区可以是父作用域,自动保存和预览各自是子作用域。关闭预览只停止预览分支,关闭整个编辑器则由父级统一结束所有分支,比散落停止句柄更容易保证完整。

不要为每个小函数无条件创建 scope。过深的所有权层次会让停止原因难追踪;只有子功能确实需要单独重启或提前结束时再建立子级,并用业务名称记录它的创建和停止。

回答前,多想一步

容易答错的地方

认为 stop 会向上影响父级
默认级联方向是拥有者到后代。子 scope 自己结束后,父级的其他 watch 和 computed 仍然活动;若业务希望一起结束,应调用共同父级或统一的关闭入口。
用代码缩进推断作用域关系
异步回调里创建的 scope 可能没有预期父级,反之辅助函数同步调用时可能加入当前 scope。应根据运行时活动作用域和 API 参数判断,而不是根据文件位置或缩进。
试着用自己的话回答

面试官还会怎么问?

父级重复 stop 会重复运行子级清理吗?

停止流程应当可以安全重复调用,已结束分支不会因再次 stop 重新激活或重复执行正常的一次性清理。外部资源自己的关闭函数也建议实现幂等,以覆盖多条结束路径。

子 scope 停止后还能再次 run 吗?

不能把已停止 scope 当作可复用开关。要重启该子功能,应创建新的子 scope 并在正确的活动父级中初始化,这样新的所有权关系才明确。

如何设计多个可独立关闭的功能?

为每个具有独立寿命的功能创建命名子 scope,由父模块保存引用和关闭函数。父级最终 stop 负责兜底,子功能按钮则只停止并替换自己的 scope。

从一道题,走向一组知识

把知识连起来

侦听与生命周期

Vue effectScope 是什么,如何一次停止其中的所有副作用?

先确认 run 的同步收集和 stop 的基本语义。

侦听与生命周期

Vue effectScope(true) 为什么容易泄漏,什么时候才该使用?

分离作用域是父级停止不再级联的明确例外。

侦听与生命周期

Vue onScopeDispose 在什么时机执行,适合清理哪些资源?

每个作用域还可以登记非响应式资源的清理动作。

参考资料

  • Vue:effectScope API
  • Vue RFC:Nested Scopes

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 嵌套关系在创建时建立
  3. 分别观察子级提前停止和父级停止
  4. 按功能边界而非文件层级嵌套
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑