Vue3组合式API中SweetAlert2在异步方法中不等待的问题
Vue3组合式API中SweetAlert2弹窗不等待按钮点击的问题解决
问题场景
在Vue3组合式API中使用SweetAlert2时遇到以下矛盾:
- 在
async修饰的onBeforeMount钩子中直接调用Swal.fire(),弹窗不会等待按钮点击就执行后续的initialiseArrays()、getRides()逻辑 - 移除
async或给Swal.fire()添加await后,弹窗能正常等待关闭
但实际业务中,Swal.fire()是在getRides函数的深层逻辑中调用的,若要每个调用都加await,就得把几乎所有关联函数都改成async,这显然增加了不必要的复杂度。尝试将getRides部分逻辑移到onMounted,但该钩子会在数据加载完成前触发,引发额外渲染问题。
核心原因
Swal.fire()本质是返回Promise的异步方法:
- 在普通同步函数中,浏览器会因模态框的线程阻塞特性,自动等待弹窗关闭后再执行后续代码
- 在
async函数中,Promise会被放入微任务队列,函数会继续向下执行,必须通过await显式等待Promise完成(即弹窗关闭)
优化解决方案
1. 局部使用async/await,避免全局修改
不需要把所有外层函数都改成async,只在直接调用Swal.fire()的局部逻辑中使用async即可:
// 仅在需要调用Swal的局部函数中使用async async function handleAlertAndFillData(data) { await Swal.fire('数据加载完成'); rides.value = data; // 填充列表的核心逻辑 } function getRides() { return fetch('/api/rides') .then(res => res.json()) .then(data => handleAlertAndFillData(data)) // 调用局部异步函数 .catch(err => { Swal.fire('加载失败', err.message, 'error'); }); } // 钩子中仅需await getRides,无需修改其他同步函数 onBeforeMount(async () => { initialiseArrays(); await getRides(); });
2. 用.then()链式调用替代await
如果不想引入async函数,可以通过Promise的.then()方法处理弹窗关闭后的逻辑,完全保留原有函数的同步状态:
function getRides() { return fetch('/api/rides') .then(res => res.json()) .then(data => { // 弹窗关闭后再执行数据填充 return Swal.fire('数据加载完成').then(() => { rides.value = data; }); }) .catch(err => { Swal.fire('加载失败', err.message, 'error'); }); }
3. 解决onMounted提前触发的问题
如果需要确保数据加载完成后再渲染页面,可以通过加载状态变量控制页面显示:
const isLoading = ref(true); async function getRides() { try { const res = await fetch('/api/rides'); const data = await res.json(); await Swal.fire('数据加载完成'); rides.value = data; } catch (err) { Swal.fire('加载失败', err.message, 'error'); } finally { isLoading.value = false; // 数据处理完成后关闭加载状态 } } onMounted(async () => { initialiseArrays(); await getRides(); });
模板中配合v-if控制渲染时机:
<template> <div v-if="!isLoading"> <!-- 页面核心内容 --> </div> <div v-else>数据加载中...</div> </template>
内容的提问来源于stack exchange,提问作者quilkin
相关产品推荐
相关产品推荐

