TypeScript中如何在同步函数内获取异步函数的返回结果?
解决同步函数中等待异步函数结果的问题
你的问题核心很明确:同步函数没法直接等待异步操作完成,因为getHolidaysByYear是异步函数,它的.then()回调会在当前同步代码执行完之后才触发,所以你看到的日志顺序是before→after→holidays,而不是你期望的顺序。下面给你两种可行的解决方案,根据你的组件场景选择:
方案一:把isHoliday改成异步函数(最直接)
既然要等待异步结果,最直接的方式就是让isHoliday本身变成异步函数,用async/await语法等待getHolidaysByYear的结果:
async function isHoliday(current : Moment) : Promise<boolean> { // 其他逻辑(缓存等) let year : number = current.toDate().getFullYear(); let dates : Date[] = []; console.log("before : " + dates.length); // 用await暂停执行,直到异步函数返回结果 dates = await getHolidaysByYear(year); console.log("after : " + dates.length); // 其他逻辑(判断current是否在节假日列表中) return dates.some(date => moment(date).isSame(current, 'day')); }
注意事项:
改完之后,调用isHoliday的地方也必须用await或者.then()来处理结果,因为它现在返回的是Promise<boolean>。比如在组件的生命周期钩子或事件处理函数中:
// 示例:React组件中调用 useEffect(() => { async function checkToday() { const isTodayHoliday = await isHoliday(moment()); console.log("今天是否是节假日?", isTodayHoliday); } checkToday(); }, []);
方案二:预加载节假日数据(适合必须同步的场景)
如果你的业务场景要求isHoliday必须是同步函数(比如某些组件渲染逻辑不支持异步),那可以提前在组件初始化时加载好节假日数据,存在状态里,让isHoliday直接使用同步的状态数据:
以React为例:
import { useState, useEffect } from 'react'; import moment from 'moment'; // 缓存已加载的节假日,避免重复请求 const holidayCache: Record<number, Date[]> = {}; async function getHolidaysByYear(year : number) : Promise<Date[]> { if (holidayCache[year]) { return holidayCache[year]; } let dates = await api.request(year); const result = dates || []; holidayCache[year] = result; console.log("holidays : " + result.length); return result; } function HolidayChecker() { const [holidays, setHolidays] = useState<Date[]>([]); const [currentYear, setCurrentYear] = useState(new Date().getFullYear()); // 初始化或年份变化时加载数据 useEffect(() => { async function loadHolidays() { const data = await getHolidaysByYear(currentYear); setHolidays(data); } loadHolidays(); }, [currentYear]); // 现在isHoliday是同步函数,直接用状态中的数据 function isHoliday(current : Moment) : boolean { const year = current.toDate().getFullYear(); // 如果当前年份未加载,先触发加载并返回默认值(或显示加载状态) if (year !== currentYear) { setCurrentYear(year); return false; } console.log("before : " + holidays.length); console.log("after : " + holidays.length); return holidays.some(date => moment(date).isSame(current, 'day')); } return ( <div> {isHoliday(moment()) ? "今天是节假日🎉" : "今天不是节假日💼"} </div> ); }
为什么你的原代码会出现顺序问题?
JavaScript是单线程的,异步操作会被放到事件队列中,等当前同步代码执行完之后才会执行。你的原代码中:
- 先打印
before : 0 - 调用
getHolidaysByYear,但它是异步的,直接进入事件队列等待 - 立刻打印
after : 0(此时dates还没被赋值) - 等接口请求完成,才会执行
.then()里的dates = values,然后打印holidays : 143
这就是为什么日志顺序和你期望的相反。
内容的提问来源于stack exchange,提问作者Bushuev
相关产品推荐
相关产品推荐

