Vue 3 响应式系统深度解析与实战应用
Orion K Lv6

Vue 3 的响应式系统是其核心特性之一,基于 ES6 Proxy 的全新实现带来了更好的性能和更强的功能。本文将深入探讨 Vue 3 响应式系统的工作原理、核心 API 的使用技巧,以及在实际项目中的最佳实践。

响应式系统核心原理

1. Proxy vs Object.defineProperty

Vue 2 的限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Vue 2 中的响应式限制
const data = {
items: ['a', 'b', 'c']
}

// 这些操作无法被检测到
data.items[0] = 'new value' // 索引赋值
data.items.length = 0 // 修改数组长度
data.newProperty = 'value' // 添加新属性
delete data.items // 删除属性

// Vue 2 需要特殊方法
Vue.set(data, 'newProperty', 'value')
Vue.delete(data, 'items')
data.items.splice(0, 1, 'new value')

Vue 3 的改进

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Vue 3 中的响应式优势
import { reactive, ref, watch } from 'vue'

const state = reactive({
items: ['a', 'b', 'c'],
count: 0
})

// 所有操作都能被检测到
watch(() => state.items, (newItems) => {
console.log('数组变化:', newItems)
}, { deep: true })

watch(() => state.count, (newCount) => {
console.log('计数变化:', newCount)
})

// 这些操作都会触发响应式更新
state.items[0] = 'new value' // ✅ 可以检测
state.items.length = 0 // ✅ 可以检测
state.newProperty = 'value' // ✅ 可以检测
delete state.items // ✅ 可以检测
state.items.push('new item') // ✅ 可以检测

2. 响应式系统架构

核心概念解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// 简化版响应式系统实现
class ReactiveEffect {
constructor(fn, scheduler = null) {
this.fn = fn
this.scheduler = scheduler
this.deps = []
this.active = true
}

run() {
if (!this.active) {
return this.fn()
}

try {
activeEffect = this
return this.fn()
} finally {
activeEffect = null
}
}

stop() {
if (this.active) {
cleanupEffect(this)
this.active = false
}
}
}

let activeEffect = null
const targetMap = new WeakMap()

// 依赖收集
function track(target, key) {
if (!activeEffect) return

let depsMap = targetMap.get(target)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}

let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = new Set()))
}

if (!dep.has(activeEffect)) {
dep.add(activeEffect)
activeEffect.deps.push(dep)
}
}

// 触发更新
function trigger(target, key, newValue, oldValue) {
const depsMap = targetMap.get(target)
if (!depsMap) return

const effects = new Set()

// 收集需要执行的 effect
const dep = depsMap.get(key)
if (dep) {
dep.forEach(effect => {
if (effect !== activeEffect) {
effects.add(effect)
}
})
}

// 执行 effects
effects.forEach(effect => {
if (effect.scheduler) {
effect.scheduler()
} else {
effect.run()
}
})
}

// 创建响应式对象
function reactive(target) {
return new Proxy(target, {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)

// 依赖收集
track(target, key)

// 如果是对象,递归创建响应式
if (typeof result === 'object' && result !== null) {
return reactive(result)
}

return result
},

set(target, key, value, receiver) {
const oldValue = target[key]
const result = Reflect.set(target, key, value, receiver)

// 触发更新
if (oldValue !== value) {
trigger(target, key, value, oldValue)
}

return result
},

deleteProperty(target, key) {
const hadKey = hasOwnProperty.call(target, key)
const oldValue = target[key]
const result = Reflect.deleteProperty(target, key)

if (result && hadKey) {
trigger(target, key, undefined, oldValue)
}

return result
}
})
}

核心 API 深度应用

1. ref 和 reactive 的选择策略

基本类型使用 ref

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import { ref, computed, watch } from 'vue'

// ✅ 基本类型推荐使用 ref
const count = ref(0)
const message = ref('Hello')
const isVisible = ref(true)

// ref 的高级用法
const userInput = ref('')

// 自定义 ref
function useDebouncedRef(value, delay = 300) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}
})
}

const debouncedInput = useDebouncedRef('')

// 模板 ref
const inputRef = ref(null)

// 在组件中使用
export default {
setup() {
const focusInput = () => {
inputRef.value?.focus()
}

return {
inputRef,
focusInput
}
}
}

复杂对象使用 reactive

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import { reactive, toRefs, computed } from 'vue'

// ✅ 复杂对象推荐使用 reactive
const state = reactive({
user: {
id: 1,
name: 'John',
profile: {
avatar: '',
bio: ''
}
},
settings: {
theme: 'light',
notifications: {
email: true,
push: false
}
},
ui: {
loading: false,
error: null,
modal: {
visible: false,
type: null
}
}
})

// 使用 toRefs 解构
const { user, settings, ui } = toRefs(state)

// 计算属性
const userDisplayName = computed(() => {
return state.user.name || state.user.profile.bio || '匿名用户'
})

const isDarkMode = computed(() => {
return state.settings.theme === 'dark'
})

// 方法
const updateUserProfile = (profileData) => {
Object.assign(state.user.profile, profileData)
}

const toggleTheme = () => {
state.settings.theme = state.settings.theme === 'light' ? 'dark' : 'light'
}

const showModal = (type) => {
state.ui.modal.visible = true
state.ui.modal.type = type
}

const hideModal = () => {
state.ui.modal.visible = false
state.ui.modal.type = null
}

2. 浅层响应式优化

shallowRef 和 shallowReactive

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import { shallowRef, shallowReactive, triggerRef } from 'vue'

// 大型数据结构优化
const largeDataSet = shallowRef({
items: new Array(10000).fill(0).map((_, i) => ({
id: i,
name: `Item ${i}`,
data: new Array(100).fill(0)
}))
})

// 手动触发更新
const updateLargeDataSet = (newData) => {
largeDataSet.value = newData
triggerRef(largeDataSet) // 手动触发响应式更新
}

// 浅层响应式对象
const shallowState = shallowReactive({
count: 0,
nested: {
value: 1 // 这个不会是响应式的
}
})

// 只有第一层属性是响应式的
shallowState.count++ // ✅ 会触发更新
shallowState.nested.value++ // ❌ 不会触发更新
shallowState.nested = { value: 2 } // ✅ 会触发更新

// 性能优化示例:虚拟滚动
function useVirtualList(items, itemHeight = 50) {
const containerRef = ref(null)
const scrollTop = ref(0)
const containerHeight = ref(0)

// 使用 shallowRef 避免深度响应式
const visibleItems = shallowRef([])

const startIndex = computed(() => {
return Math.floor(scrollTop.value / itemHeight)
})

const endIndex = computed(() => {
const visibleCount = Math.ceil(containerHeight.value / itemHeight)
return Math.min(startIndex.value + visibleCount + 1, items.length)
})

const updateVisibleItems = () => {
visibleItems.value = items.slice(startIndex.value, endIndex.value)
triggerRef(visibleItems)
}

watch([startIndex, endIndex], updateVisibleItems, { immediate: true })

const onScroll = (event) => {
scrollTop.value = event.target.scrollTop
}

return {
containerRef,
visibleItems,
onScroll,
startIndex,
endIndex
}
}

3. 只读和非响应式数据

readonly 和 markRaw

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import { reactive, readonly, markRaw, isReactive, isReadonly } from 'vue'

// 创建只读状态
const state = reactive({
count: 0,
user: {
name: 'John'
}
})

const readonlyState = readonly(state)

// 尝试修改只读状态会在开发环境发出警告
// readonlyState.count++ // 警告:Set operation on key "count" failed: target is readonly

// 但原始状态仍然可以修改
state.count++ // ✅ 正常工作

// 标记非响应式数据
const nonReactiveData = markRaw({
heavyObject: new Map(),
thirdPartyInstance: new SomeLibrary(),
largeArray: new Array(100000).fill(0)
})

const appState = reactive({
data: nonReactiveData, // 这个对象不会被转换为响应式
settings: {
theme: 'light'
}
})

console.log(isReactive(appState.data)) // false
console.log(isReactive(appState.settings)) // true

// 实际应用:配置管理
class ConfigManager {
constructor() {
// 配置数据标记为非响应式,避免不必要的性能开销
this.config = markRaw({
api: {
baseURL: 'https://api.example.com',
timeout: 5000,
retries: 3
},
features: {
enableAnalytics: true,
enableNotifications: false
},
constants: {
MAX_FILE_SIZE: 10 * 1024 * 1024,
SUPPORTED_FORMATS: ['jpg', 'png', 'gif']
}
})

// 运行时状态保持响应式
this.state = reactive({
isLoading: false,
error: null,
lastUpdated: null
})
}

getConfig(path) {
return path.split('.').reduce((obj, key) => obj?.[key], this.config)
}

async updateConfig(newConfig) {
this.state.isLoading = true
this.state.error = null

try {
// 更新配置(非响应式)
Object.assign(this.config, newConfig)
this.state.lastUpdated = Date.now()
} catch (error) {
this.state.error = error.message
} finally {
this.state.isLoading = false
}
}
}

const configManager = new ConfigManager()

高级响应式模式

1. 计算属性的深度应用

缓存和依赖优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { computed, ref, watch } from 'vue'

// 昂贵计算的缓存
function useExpensiveComputation(source) {
const cache = new Map()

const result = computed(() => {
const key = JSON.stringify(source.value)

if (cache.has(key)) {
console.log('从缓存获取结果')
return cache.get(key)
}

console.log('执行昂贵计算')
const computed = expensiveFunction(source.value)
cache.set(key, computed)

// 限制缓存大小
if (cache.size > 100) {
const firstKey = cache.keys().next().value
cache.delete(firstKey)
}

return computed
})

return result
}

// 条件计算属性
function useConditionalComputed(condition, computeFn, fallback = null) {
return computed(() => {
return condition.value ? computeFn() : fallback
})
}

// 使用示例
const isDataReady = ref(false)
const rawData = ref([])

const processedData = useConditionalComputed(
isDataReady,
() => rawData.value.map(item => ({ ...item, processed: true })),
[]
)

// 异步计算属性
function useAsyncComputed(asyncFn, initialValue = null) {
const result = ref(initialValue)
const isLoading = ref(false)
const error = ref(null)

const execute = async () => {
isLoading.value = true
error.value = null

try {
const value = await asyncFn()
result.value = value
} catch (err) {
error.value = err
} finally {
isLoading.value = false
}
}

return {
result: readonly(result),
isLoading: readonly(isLoading),
error: readonly(error),
execute
}
}

// 使用异步计算属性
const userId = ref(1)
const {
result: userProfile,
isLoading: isLoadingProfile,
error: profileError,
execute: fetchProfile
} = useAsyncComputed(async () => {
const response = await fetch(`/api/users/${userId.value}`)
return response.json()
})

// 监听 userId 变化自动重新获取
watch(userId, fetchProfile, { immediate: true })

2. 侦听器的高级用法

深度侦听和性能优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import { watch, watchEffect, ref, reactive } from 'vue'

// 智能深度侦听
function useSmartWatch(source, callback, options = {}) {
const { deep = false, immediate = false, debounce = 0 } = options

let timeoutId = null

const debouncedCallback = (...args) => {
if (debounce > 0) {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => callback(...args), debounce)
} else {
callback(...args)
}
}

return watch(source, debouncedCallback, { deep, immediate })
}

// 条件侦听
function useConditionalWatch(source, callback, condition) {
return watch(
source,
(newValue, oldValue) => {
if (condition(newValue, oldValue)) {
callback(newValue, oldValue)
}
}
)
}

// 批量侦听
function useBatchWatch(sources, callback, options = {}) {
const { batchSize = 10, delay = 100 } = options
const changes = []
let timeoutId = null

const flushChanges = () => {
if (changes.length > 0) {
callback([...changes])
changes.length = 0
}
}

sources.forEach((source, index) => {
watch(source, (newValue, oldValue) => {
changes.push({ index, newValue, oldValue })

// 达到批量大小或设置延迟后执行
if (changes.length >= batchSize) {
clearTimeout(timeoutId)
flushChanges()
} else {
clearTimeout(timeoutId)
timeoutId = setTimeout(flushChanges, delay)
}
})
})

return flushChanges
}

// 使用示例
const formData = reactive({
name: '',
email: '',
phone: '',
address: ''
})

// 防抖侦听表单变化
useSmartWatch(
formData,
(newData) => {
console.log('表单数据变化:', newData)
// 自动保存草稿
saveDraft(newData)
},
{ deep: true, debounce: 500 }
)

// 条件侦听:只在有效数据时触发
useConditionalWatch(
() => formData.email,
(newEmail) => {
console.log('邮箱验证:', newEmail)
validateEmail(newEmail)
},
(newEmail) => newEmail && newEmail.includes('@')
)

// 侦听器清理
function useWatchWithCleanup(source, callback) {
let cleanup = null

const stopWatcher = watch(
source,
async (newValue, oldValue, onCleanup) => {
// 清理上一次的副作用
if (cleanup) {
cleanup()
}

// 执行新的副作用
cleanup = await callback(newValue, oldValue)

// 注册清理函数
onCleanup(() => {
if (cleanup) {
cleanup()
cleanup = null
}
})
}
)

return stopWatcher
}

// 使用示例:搜索建议
const searchQuery = ref('')
const suggestions = ref([])

useWatchWithCleanup(
searchQuery,
async (query) => {
if (!query.trim()) {
suggestions.value = []
return null
}

const controller = new AbortController()

try {
const response = await fetch(`/api/search?q=${query}`, {
signal: controller.signal
})
const data = await response.json()
suggestions.value = data.suggestions
} catch (error) {
if (error.name !== 'AbortError') {
console.error('搜索失败:', error)
}
}

// 返回清理函数
return () => {
controller.abort()
}
}
)

3. 响应式数据的序列化和持久化

状态持久化方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import { reactive, watch, toRaw } from 'vue'

// 响应式状态持久化
class PersistentStore {
constructor(key, initialState = {}, options = {}) {
this.key = key
this.options = {
storage: localStorage,
serializer: JSON,
debounce: 300,
...options
}

// 从存储中恢复状态
const savedState = this.loadState()
this.state = reactive({ ...initialState, ...savedState })

// 监听状态变化并持久化
this.setupPersistence()
}

loadState() {
try {
const saved = this.options.storage.getItem(this.key)
return saved ? this.options.serializer.parse(saved) : {}
} catch (error) {
console.error('加载状态失败:', error)
return {}
}
}

saveState() {
try {
// 使用 toRaw 获取原始对象,避免序列化响应式代理
const rawState = toRaw(this.state)
const serialized = this.options.serializer.stringify(rawState)
this.options.storage.setItem(this.key, serialized)
} catch (error) {
console.error('保存状态失败:', error)
}
}

setupPersistence() {
let timeoutId = null

watch(
this.state,
() => {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
this.saveState()
}, this.options.debounce)
},
{ deep: true }
)
}

reset() {
Object.keys(this.state).forEach(key => {
delete this.state[key]
})
this.options.storage.removeItem(this.key)
}

clear() {
this.options.storage.removeItem(this.key)
}
}

// 使用示例
const userPreferences = new PersistentStore('userPreferences', {
theme: 'light',
language: 'zh-CN',
sidebarCollapsed: false
})

// 状态变化会自动持久化
userPreferences.state.theme = 'dark'
userPreferences.state.language = 'en-US'

// 跨组件状态管理
function createGlobalStore(name, initialState) {
const stores = new Map()

return function useStore() {
if (!stores.has(name)) {
const store = new PersistentStore(name, initialState)
stores.set(name, store)
}

return stores.get(name).state
}
}

const useAppStore = createGlobalStore('app', {
user: null,
isAuthenticated: false,
permissions: []
})

const useUIStore = createGlobalStore('ui', {
loading: false,
notifications: [],
modal: {
visible: false,
component: null
}
})

// 在组件中使用
export default {
setup() {
const appState = useAppStore()
const uiState = useUIStore()

const login = async (credentials) => {
uiState.loading = true
try {
const user = await authAPI.login(credentials)
appState.user = user
appState.isAuthenticated = true
appState.permissions = user.permissions
} catch (error) {
uiState.notifications.push({
type: 'error',
message: '登录失败'
})
} finally {
uiState.loading = false
}
}

return {
appState,
uiState,
login
}
}
}

性能优化最佳实践

1. 响应式数据的性能监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// 响应式性能监控
class ReactivityProfiler {
constructor() {
this.effects = new Map()
this.computedCache = new Map()
this.watcherStats = new Map()
}

trackEffect(effect, duration) {
const key = effect.fn.name || 'anonymous'
if (!this.effects.has(key)) {
this.effects.set(key, { count: 0, totalTime: 0, maxTime: 0 })
}

const stats = this.effects.get(key)
stats.count++
stats.totalTime += duration
stats.maxTime = Math.max(stats.maxTime, duration)
}

trackComputed(key, hit) {
if (!this.computedCache.has(key)) {
this.computedCache.set(key, { hits: 0, misses: 0 })
}

const stats = this.computedCache.get(key)
if (hit) {
stats.hits++
} else {
stats.misses++
}
}

getReport() {
return {
effects: Array.from(this.effects.entries()).map(([name, stats]) => ({
name,
...stats,
avgTime: stats.totalTime / stats.count
})),
computedCache: Array.from(this.computedCache.entries()).map(([name, stats]) => ({
name,
...stats,
hitRate: stats.hits / (stats.hits + stats.misses)
}))
}
}

reset() {
this.effects.clear()
this.computedCache.clear()
this.watcherStats.clear()
}
}

const profiler = new ReactivityProfiler()

// 性能监控装饰器
function withPerformanceTracking(fn, name) {
return function(...args) {
const start = performance.now()
const result = fn.apply(this, args)
const duration = performance.now() - start

profiler.trackEffect({ fn: { name } }, duration)

if (duration > 16) { // 超过一帧的时间
console.warn(`慢响应式更新检测: ${name} 耗时 ${duration.toFixed(2)}ms`)
}

return result
}
}

// 使用示例
const expensiveComputed = computed(
withPerformanceTracking(() => {
// 昂贵的计算
return largeArray.value.reduce((sum, item) => sum + item.value, 0)
}, 'expensiveComputed')
)

2. 内存泄漏检测和预防

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// 内存泄漏检测
class MemoryLeakDetector {
constructor() {
this.watchers = new Set()
this.effects = new Set()
this.timers = new Set()
}

trackWatcher(stopFn) {
this.watchers.add(stopFn)
return () => {
stopFn()
this.watchers.delete(stopFn)
}
}

trackEffect(effect) {
this.effects.add(effect)
return () => {
effect.stop()
this.effects.delete(effect)
}
}

trackTimer(timerId) {
this.timers.add(timerId)
return () => {
clearTimeout(timerId)
clearInterval(timerId)
this.timers.delete(timerId)
}
}

cleanup() {
// 清理所有侦听器
this.watchers.forEach(stop => stop())
this.watchers.clear()

// 清理所有副作用
this.effects.forEach(effect => effect.stop())
this.effects.clear()

// 清理所有定时器
this.timers.forEach(timerId => {
clearTimeout(timerId)
clearInterval(timerId)
})
this.timers.clear()
}

getStats() {
return {
watchers: this.watchers.size,
effects: this.effects.size,
timers: this.timers.size
}
}
}

// 安全的组合式函数
function useSafeComposable() {
const detector = new MemoryLeakDetector()

onUnmounted(() => {
detector.cleanup()
})

const safeWatch = (source, callback, options) => {
const stop = watch(source, callback, options)
return detector.trackWatcher(stop)
}

const safeSetTimeout = (callback, delay) => {
const timerId = setTimeout(callback, delay)
detector.trackTimer(timerId)
return timerId
}

const safeSetInterval = (callback, delay) => {
const timerId = setInterval(callback, delay)
detector.trackTimer(timerId)
return timerId
}

return {
safeWatch,
safeSetTimeout,
safeSetInterval,
getMemoryStats: () => detector.getStats()
}
}

// 使用示例
export default {
setup() {
const { safeWatch, safeSetTimeout, getMemoryStats } = useSafeComposable()

const count = ref(0)

// 安全的侦听器,会在组件卸载时自动清理
safeWatch(count, (newValue) => {
console.log('计数变化:', newValue)
})

// 安全的定时器,会在组件卸载时自动清理
safeSetTimeout(() => {
count.value++
}, 1000)

// 开发环境下监控内存使用
if (process.env.NODE_ENV === 'development') {
safeSetInterval(() => {
console.log('内存统计:', getMemoryStats())
}, 5000)
}

return {
count
}
}
}

总结

Vue 3 的响应式系统基于 Proxy 的实现带来了显著的改进:

  1. 更强的检测能力:能够检测数组索引赋值、属性添加/删除等操作
  2. 更好的性能:按需代理、浅层响应式等优化手段
  3. 更灵活的 API:ref、reactive、readonly、markRaw 等提供了更多选择
  4. 更好的 TypeScript 支持:完整的类型推导和检查

在实际开发中,应该:

  • 根据数据类型选择合适的响应式 API
  • 合理使用浅层响应式和非响应式标记进行性能优化
  • 注意内存泄漏的预防和检测
  • 在复杂应用中建立响应式数据的监控机制

掌握这些原理和技巧,能够帮助我们构建更高效、更可维护的 Vue 3 应用。

本站由 提供部署服务