Vue 3 onMounted 中控制同步与异步执行策略
在 Vue 3 的 onMounted 钩子中,控制多个函数的同步和异步执行有多种方法。以下是详细的技术方案:
📊 核心概念对比
| 执行方式 | 特点 | 适用场景 |
|---|---|---|
| 同步执行 | 顺序执行,前一个完成后才开始下一个 | 有依赖关系的操作 |
| 并行执行 | 同时启动,等待所有完成 | 独立的任务,提高效率 |
| 按条件执行 | 根据条件决定是否执行 | 条件加载、权限控制 |
一、同步执行控制
1. 基本同步顺序执行
javascript
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
console.log('1. 开始同步执行')
// 函数1
const result1 = function1()
console.log('函数1完成:', result1)
// 函数2(依赖函数1的结果)
const result2 = function2(result1)
console.log('函数2完成:', result2)
// 函数3(依赖函数2的结果)
const result3 = function3(result2)
console.log('函数3完成:', result3)
console.log('所有同步函数执行完成')
})
function function1() {
console.log('执行 function1')
return 'function1 的结果'
}
function function2(input) {
console.log('执行 function2,输入:', input)
return input + ' -> 经过function2处理'
}
function function3(input) {
console.log('执行 function3,输入:', input)
return input + ' -> 经过function3处理'
}
</script>
输出:
1. 开始同步执行
执行 function1
函数1完成: function1 的结果
执行 function2,输入: function1 的结果
函数2完成: function1 的结果 -> 经过function2处理
执行 function3,输入: function1 的结果 -> 经过function2处理
函数3完成: function1 的结果 -> 经过function2处理 -> 经过function3处理
所有同步函数执行完成
2. 使用 async/await 控制异步函数同步执行
javascript
<script setup>
import { onMounted } from 'vue'
onMounted(async () => {
console.log('🚀 开始顺序执行异步任务')
try {
// 1. 等待第一个异步任务完成
const user = await fetchUserData()
console.log('✅ 用户数据获取完成:', user.name)
// 2. 等待第二个异步任务(依赖第一个结果)
const orders = await fetchUserOrders(user.id)
console.log('✅ 订单数据获取完成,数量:', orders.length)
// 3. 等待第三个异步任务
const analytics = await initAnalytics(orders)
console.log('✅ 分析工具初始化完成')
console.log('🎉 所有任务顺序执行完成')
} catch (error) {
console.error('❌ 执行失败:', error)
}
})
// 模拟异步函数
async function fetchUserData() {
return new Promise(resolve => {
setTimeout(() => {
resolve({ id: 1, name: '张三' })
}, 1000)
})
}
async function fetchUserOrders(userId) {
return new Promise(resolve => {
setTimeout(() => {
resolve([{ id: 1, product: '商品A' }, { id: 2, product: '商品B' }])
}, 1500)
})
}
async function initAnalytics(orders) {
return new Promise(resolve => {
setTimeout(() => {
resolve({ events: orders.length })
}, 500)
})
}
</script>
执行时间:约 3 秒(1000 + 1500 + 500)
二、并行执行控制
1. 使用 Promise.all 并行执行
javascript
<script setup>
import { onMounted, ref } from 'vue'
const loading = ref(true)
const data = ref({})
onMounted(async () => {
console.log('🚀 开始并行执行任务')
const startTime = Date.now()
try {
// 并行执行所有异步任务
const [userData, configData, permissions] = await Promise.all([
fetchUserData(),
fetchConfigData(),
fetchUserPermissions()
])
const endTime = Date.now()
console.log(`✅ 所有并行任务完成,耗时: ${endTime - startTime}ms`)
// 整合数据
data.value = { ...userData, ...configData, permissions }
loading.value = false
console.log('🎉 数据整合完成:', data.value)
} catch (error) {
console.error('❌ 并行执行失败:', error)
loading.value = false
}
})
async function fetchUserData() {
return new Promise(resolve => {
setTimeout(() => {
console.log('✅ 用户数据获取完成')
resolve({ name: '张三', age: 25 })
}, 2000) // 模拟2秒延迟
})
}
async function fetchConfigData() {
return new Promise(resolve => {
setTimeout(() => {
console.log('✅ 配置数据获取完成')
resolve({ theme: 'dark', language: 'zh-CN' })
}, 1500) // 模拟1.5秒延迟
})
}
async function fetchUserPermissions() {
return new Promise(resolve => {
setTimeout(() => {
console.log('✅ 权限数据获取完成')
resolve(['read', 'write', 'delete'])
}, 1000) // 模拟1秒延迟
})
}
</script>
输出:
🚀 开始并行执行任务
✅ 权限数据获取完成
✅ 配置数据获取完成
✅ 用户数据获取完成
✅ 所有并行任务完成,耗时: 2002ms
🎉 数据整合完成: {name: '张三', age: 25, theme: 'dark', language: 'zh-CN', permissions: ['read', 'write', 'delete']}
总耗时:约 2 秒(最慢的任务耗时)
2. 使用 Promise.allSettled 处理并行任务(不因失败中断)
javascript
<script setup>
import { onMounted, ref } from 'vue'
const results = ref({})
onMounted(async () => {
console.log('🚀 开始并行执行任务(包含容错)')
// 使用 allSettled,即使某个任务失败也不会中断
const settledResults = await Promise.allSettled([
fetchUserData(),
fetchConfigData(),
fetchUserPermissions(),
fetchOptionalData() // 这个可能失败
])
// 处理结果
const successResults = {}
const failedResults = {}
settledResults.forEach((result, index) => {
if (result.status === 'fulfilled') {
successResults[`task${index}`] = result.value
} else {
failedResults[`task${index}`] = result.reason
}
})
results.value = { success: successResults, failed: failedResults }
console.log('📊 执行结果:', results.value)
})
async function fetchUserData() {
return Promise.resolve({ user: '张三' })
}
async function fetchConfigData() {
return Promise.resolve({ theme: 'dark' })
}
async function fetchUserPermissions() {
return Promise.resolve(['read', 'write'])
}
async function fetchOptionalData() {
// 模拟可能失败的任务
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
resolve({ optional: 'data' })
} else {
reject(new Error('Optional data fetch failed'))
}
}, 500)
})
}
</script>
三、混合执行策略
1. 分组并行 + 顺序执行
javascript
<script setup>
import { onMounted, ref } from 'vue'
const executionLog = ref([])
onMounted(async () => {
console.log('🚀 开始混合执行策略')
addLog('开始执行')
try {
// 阶段1:并行加载不依赖的数据
addLog('阶段1: 并行加载基础数据')
const [user, config] = await Promise.all([
fetchUserData(),
fetchConfigData()
])
addLog('阶段1完成')
// 阶段2:顺序执行依赖任务
addLog('阶段2: 顺序加载依赖数据')
const orders = await fetchUserOrders(user.id)
addLog('订单数据加载完成')
const analytics = await initAnalytics(orders)
addLog('分析工具初始化完成')
// 阶段3:并行执行最后步骤
addLog('阶段3: 并行执行清理和通知')
await Promise.all([
sendAnalytics(analytics),
updateUserLastLogin(user.id)
])
addLog('阶段3完成')
addLog('🎉 所有任务完成')
} catch (error) {
addLog(`❌ 执行失败: ${error.message}`)
}
})
function addLog(message) {
const timestamp = new Date().toLocaleTimeString()
executionLog.value.push(`${timestamp}: ${message}`)
console.log(message)
}
// 模拟函数
async function fetchUserData() {
await delay(1000)
return { id: 1, name: '张三' }
}
async function fetchConfigData() {
await delay(800)
return { theme: 'dark' }
}
async function fetchUserOrders() {
await delay(1200)
return [{ id: 1 }, { id: 2 }]
}
async function initAnalytics() {
await delay(600)
return { initialized: true }
}
async function sendAnalytics() {
await delay(300)
}
async function updateUserLastLogin() {
await delay(400)
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
</script>
执行时间:约 3.6 秒(1000 + 1200 + 600 + 400)
2. 带并发限制的并行执行
javascript
<script setup>
import { onMounted, ref } from 'vue'
const tasks = ref(Array.from({ length: 10 }, (_, i) => ({
id: i + 1,
status: 'pending',
result: null
})))
onMounted(async () => {
console.log('🚀 开始带并发限制的执行')
// 并发数限制为3
const concurrencyLimit = 3
const taskPromises = tasks.value.map(task => task.id)
// 分批次执行
for (let i = 0; i < taskPromises.length; i += concurrencyLimit) {
const batch = taskPromises.slice(i, i + concurrencyLimit)
console.log(`执行批次 ${i / concurrencyLimit + 1}: 任务 ${batch.join(', ')}`)
// 并行执行当前批次
const batchPromises = batch.map(async taskId => {
const task = tasks.value.find(t => t.id === taskId)
task.status = 'running'
try {
const result = await simulateTask(taskId)
task.status = 'completed'
task.result = result
console.log(`✅ 任务 ${taskId} 完成`)
} catch (error) {
task.status = 'failed'
task.result = error.message
console.log(`❌ 任务 ${taskId} 失败`)
}
})
// 等待当前批次所有任务完成
await Promise.all(batchPromises)
}
console.log('🎉 所有批次执行完成')
})
async function simulateTask(taskId) {
// 模拟随机耗时任务
const duration = 500 + Math.random() * 1000
await delay(duration)
// 模拟10%的失败率
if (Math.random() < 0.1) {
throw new Error(`任务 ${taskId} 模拟失败`)
}
return `任务 ${taskId} 结果,耗时 ${Math.round(duration)}ms`
}
</script>
四、高级控制模式
1. 使用队列控制执行顺序
javascript
<script setup>
import { onMounted, ref } from 'vue'
class TaskQueue {
constructor(concurrency = 1) {
this.concurrency = concurrency
this.running = 0
this.queue = []
}
add(task) {
return new Promise((resolve, reject) => {
this.queue.push({ task, resolve, reject })
this.run()
})
}
run() {
while (this.running < this.concurrency && this.queue.length) {
const { task, resolve, reject } = this.queue.shift()
this.running++
task()
.then(resolve)
.catch(reject)
.finally(() => {
this.running--
this.run()
})
}
}
}
const executionOrder = ref([])
onMounted(async () => {
console.log('🚀 使用队列控制执行顺序')
// 创建并发数为2的队列
const queue = new TaskQueue(2)
// 添加任务到队列
const tasks = [
() => simulateTask('任务A', 1000),
() => simulateTask('任务B', 800),
() => simulateTask('任务C', 1200),
() => simulateTask('任务D', 600),
() => simulateTask('任务E', 900)
]
// 记录执行顺序
const addToOrder = (taskName) => {
executionOrder.value.push({
time: Date.now(),
task: taskName
})
}
// 并行执行所有任务(但限制并发数)
const startTime = Date.now()
addToOrder('开始执行')
await Promise.all(tasks.map((task, index) =>
queue.add(async () => {
addToOrder(`开始 ${task.name}`)
await task()
addToOrder(`完成 ${task.name}`)
})
))
addToOrder(`全部完成,总耗时: ${Date.now() - startTime}ms`)
console.log('📊 执行顺序:', executionOrder.value)
})
async function simulateTask(name, duration) {
console.log(`开始执行 ${name}`)
await delay(duration)
console.log(`完成 ${name}`)
return name
}
</script>
2. 使用 async/await 生成器控制流程
javascript
<script setup>
import { onMounted, ref } from 'vue'
const steps = ref([])
onMounted(async () => {
console.log('🚀 使用生成器控制执行流程')
// 定义任务生成器
async function* taskGenerator() {
steps.value.push('1. 初始化')
yield await initApp()
steps.value.push('2. 加载用户数据')
const user = yield await loadUserData()
steps.value.push('3. 根据用户角色加载不同数据')
if (user.role === 'admin') {
yield await loadAdminData()
} else {
yield await loadUserSpecificData(user.id)
}
steps.value.push('4. 完成初始化')
yield await finalizeInit()
}
// 执行生成器
const generator = taskGenerator()
let result = await generator.next()
while (!result.done) {
console.log('步骤完成:', result.value)
result = await generator.next()
}
console.log('🎉 所有步骤完成')
console.log('步骤记录:', steps.value)
})
async function initApp() {
await delay(500)
return '应用初始化完成'
}
async function loadUserData() {
await delay(800)
return { id: 1, name: '张三', role: 'admin' }
}
async function loadAdminData() {
await delay(1000)
return '管理员数据加载完成'
}
async function loadUserSpecificData() {
await delay(600)
return '用户数据加载完成'
}
async function finalizeInit() {
await delay(300)
return '初始化完成'
}
</script>
五、错误处理与重试机制
1. 带重试的异步执行
javascript
<script setup>
import { onMounted, ref } from 'vue'
const attempts = ref({})
onMounted(async () => {
console.log('🚀 开始带重试机制的执行')
// 重试配置
const retryConfig = {
maxRetries: 3,
retryDelay: 1000,
onRetry: (taskName, attempt) => {
console.log(`🔄 ${taskName} 第 ${attempt} 次重试`)
}
}
// 执行带重试的任务
const result = await executeWithRetry(
fetchCriticalData,
['关键数据'],
retryConfig
)
console.log('📊 最终结果:', result)
})
// 重试执行器
async function executeWithRetry(task, args, config) {
const { maxRetries, retryDelay, onRetry } = config
let lastError
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
if (attempt > 0 && onRetry) {
onRetry(task.name, attempt)
}
attempts.value[task.name] = (attempts.value[task.name] || 0) + 1
return await task(...args)
} catch (error) {
lastError = error
console.log(`❌ ${task.name} 第 ${attempt} 次失败:`, error.message)
if (attempt < maxRetries) {
await delay(retryDelay)
}
}
}
throw lastError
}
// 模拟可能失败的任务
async function fetchCriticalData() {
const shouldFail = Math.random() < 0.7 // 70%失败率
await delay(300)
if (shouldFail) {
throw new Error('网络请求失败')
}
return { data: '重要数据' }
}
</script>
六、最佳实践总结
同步执行场景
javascript
// 适用于有依赖关系的任务
onMounted(async () => {
const data1 = await task1() // 必须先完成
const data2 = await task2(data1) // 依赖data1
const data3 = await task3(data2) // 依赖data2
})
并行执行场景
javascript
// 适用于独立任务,提高效率
onMounted(async () => {
const [result1, result2, result3] = await Promise.all([
task1(), // 独立任务
task2(), // 独立任务
task3() // 独立任务
])
})
混合执行场景
javascript
// 组合使用,先并行后顺序
onMounted(async () => {
// 并行加载基础数据
const [user, config] = await Promise.all([
fetchUser(),
fetchConfig()
])
// 顺序处理依赖数据
const orders = await fetchOrders(user.id)
await processOrders(orders)
// 最后并行清理
await Promise.all([
sendAnalytics(),
updateCache()
])
})
错误处理最佳实践
javascript
onMounted(async () => {
try {
// 主任务
await mainTask()
} catch (error) {
console.error('主任务失败:', error)
// 降级处理
await fallbackTask()
} finally {
// 清理资源
await cleanup()
}
})
性能监控
javascript
onMounted(async () => {
const startTime = performance.now()
// 执行任务
await yourTasks()
const endTime = performance.now()
console.log(`⏱️ 执行耗时: ${Math.round(endTime - startTime)}ms`)
// 可以发送到监控系统
if (endTime - startTime > 2000) {
console.warn('⚠️ 执行时间过长')
}
})
🎯 核心要点
- 使用
await控制顺序执行 - 使用
Promise.all()控制并行执行 - 使用
Promise.allSettled()处理可能失败的任务 - 合理组合顺序和并行执行优化性能
- 实现适当的错误处理和重试机制
- 使用队列控制并发数,避免资源耗尽
通过合理选择执行策略,可以显著优化组件初始化的性能和用户体验。