如何在TypeScript同步函数中获取异步函数的返回结果?
解决同步函数中等待异步结果的问题
这问题我太熟了——你现在的核心痛点就是同步函数没办法直接等待异步操作完成。JavaScript的事件循环机制决定了,异步代码(比如getHolidaysByYear里的await和后续的.then回调)会在所有同步代码执行完之后才会触发,所以你看到的日志顺序才是before:0、after:0先输出,最后才是holidays:143。
下面给你两种实用的解决方案,适配不同的组件使用场景:
方案一:把isHoliday改成异步函数,组件中处理异步逻辑
既然依赖的是异步接口,最直接的方式就是让isHoliday也变成异步函数,然后在组件里用async/await来处理结果。同时别忘了加缓存,避免重复请求接口。
修改后的代码示例
// 保留原异步接口,简化空值处理 async function getHolidaysByYear(year: number): Promise<Date[]> { const dates = await api.request(year); return dates ?? []; } // 全局缓存,避免重复请求 const holidayCache = new Map<number, Date[]>(); // 改为异步函数 async function isHoliday(current: Moment): Promise<boolean> { const year = current.toDate().getFullYear(); let dates: Date[]; // 先查缓存,有就直接用 if (holidayCache.has(year)) { dates = holidayCache.get(year)!; } else { // 没有就调用接口,并存进缓存 dates = await getHolidaysByYear(year); holidayCache.set(year, dates); console.log("holidays:", dates.length); } console.log("after:", dates.length); // 核心判断逻辑:检查当前日期是否在节假日列表中 return dates.some(date => moment(date).isSame(current, 'day')); }
组件中使用示例(以React为例)
function HolidayDisplay({ currentDate }: { currentDate: Moment }) { const [isHolidayResult, setIsHolidayResult] = useState<boolean | null>(null); const [loading, setLoading] = useState(true); useEffect(() => { // 用异步函数包裹,处理isHoliday的结果 const checkHoliday = async () => { setLoading(true); const result = await isHoliday(currentDate); setIsHolidayResult(result); setLoading(false); }; checkHoliday(); }, [currentDate]); if (loading) return <div>正在查询节假日...</div>; return ( <div> {isHolidayResult ? "🎉 今天是节假日!" : "💼 今天是工作日"} </div> ); }
方案二:预加载节假日数据,让isHoliday保持同步
如果你的组件必须在同步逻辑中使用isHoliday(比如渲染时直接判断),可以提前在组件挂载阶段预加载需要的年份数据,存到缓存里。这样isHoliday执行时就能直接拿到同步的缓存数据。
预加载+同步判断的代码示例
// 全局缓存和加载状态(避免重复请求) const holidayCache = new Map<number, Date[]>(); const loadingPromises = new Map<number, Promise<void>>(); // 预加载指定年份的节假日数据 async function preloadHolidays(year: number) { // 已有缓存直接返回 if (holidayCache.has(year)) return; // 正在加载就等待加载完成 if (loadingPromises.has(year)) await loadingPromises.get(year); // 发起请求并更新缓存 const loadPromise = (async () => { const dates = await getHolidaysByYear(year); holidayCache.set(year, dates); console.log("holidays:", dates.length); })(); loadingPromises.set(year, loadPromise); await loadPromise; loadingPromises.delete(year); } // 保持同步的isHoliday,前提是数据已预加载 function isHoliday(current: Moment): boolean { const year = current.toDate().getFullYear(); const dates = holidayCache.get(year) || []; console.log("after:", dates.length); return dates.some(date => moment(date).isSame(current, 'day')); }
组件中使用示例
function HolidayDisplay({ currentDate }: { currentDate: Moment }) { const [dataLoaded, setDataLoaded] = useState(false); useEffect(() => { const year = currentDate.toDate().getFullYear(); // 组件挂载时预加载对应年份的节假日数据 preloadHolidays(year).then(() => setDataLoaded(true)); }, [currentDate]); if (!dataLoaded) return <div>加载中...</div>; return ( <div> {isHoliday(currentDate) ? "🎉 今天是节假日!" : "💼 今天是工作日"} </div> ); }
方案选择建议
- 如果
isHoliday是在**用户交互(比如点击按钮)**时触发,方案一更简单直接; - 如果
isHoliday是在组件渲染阶段就需要用到,方案二更合适,避免渲染逻辑中混入异步代码导致的问题。
内容的提问来源于stack exchange,提问作者Bushuev
相关产品推荐
相关产品推荐

