如何正确await异步防抖函数?解决await立即生效问题
问题:await防抖后的异步API调用未生效,控制台立即打印'Awaited'
我尝试await一个经过防抖处理的异步API调用,但await未生效,控制台会立即打印'Awaited',想知道哪里出错了。
我的代码
onMounted中的代码
onMounted(async () => { console.log('Awaiting'); const fetchAbsentiesAsync = await apiCallConst(); await Promise.all([fetchAbsentiesAsync]); console.log('Awaited'); isLoading.value = false; });
API调用代码
import debounce from 'lodash/debounce'; const apiCallConst = debounce(async () => { await ApiService.makeApiCall() .then((data) => { state.data = data; }) }, 10000);
ApiService.makeApiCall代码
async makeApiCall(): Promise<string> { return { data: await apiFetch(`group/data`, { method: HttpMethods.POST, }), }; }
问题原因
lodash的debounce函数默认不会返回原异步函数的Promise,它返回的防抖函数调用后,不会等待内部的异步操作完成,而是直接返回undefined。所以你这里的await apiCallConst()实际上是在等待一个undefined,自然会立即执行后续代码,不会等待防抖后的API请求完成。
另外原代码里还有两处冗余:
const fetchAbsentiesAsync = await apiCallConst();因为apiCallConst()返回undefined,所以这个变量没有意义await Promise.all([fetchAbsentiesAsync])等同于等待一个包含undefined的数组,完全起不到等待异步操作的作用
解决方案
方案1:封装支持Promise的防抖函数
自己实现一个能返回Promise的防抖函数,让调用者可以通过await等待防抖后的异步操作完成:
function debouncePromise(func, wait) { let timeoutId; let resolveQueue = []; return function(...args) { return new Promise((resolve) => { clearTimeout(timeoutId); timeoutId = setTimeout(async () => { const result = await func.apply(this, args); // 批量resolve所有等待的Promise resolveQueue.forEach(r => r(result)); resolveQueue = []; }, wait); resolveQueue.push(resolve); }); }; }
然后用这个函数替换lodash的debounce:
const apiCallConst = debouncePromise(async () => { const data = await ApiService.makeApiCall(); state.data = data; }, 10000);
这样在onMounted中调用await apiCallConst()就会正确等待防抖后的API请求完成,之后才会打印'Awaited'。
方案2:简化原代码逻辑(如果不需要防抖的累积处理)
如果只是想要延迟执行一次API调用,不需要防抖的“多次触发取最后一次”的特性,可以直接用setTimeout配合Promise:
const apiCallConst = () => { return new Promise(resolve => { setTimeout(async () => { const data = await ApiService.makeApiCall(); state.data = data; resolve(data); }, 10000); }); };
这样同样可以通过await apiCallConst()等待操作完成。
额外优化建议
原API调用代码中混用了await和.then(),可以简化为纯await写法,提升可读性:
// 优化后的apiCallConst(配合自定义的debouncePromise) const apiCallConst = debouncePromise(async () => { const data = await ApiService.makeApiCall(); state.data = data; }, 10000);
内容的提问来源于stack exchange,提问作者Ruben
相关产品推荐
相关产品推荐

