React.JS中API调用使用stale陈旧值问题如何解决
问题根因
该问题是典型的Promise异步时序错误,和并行逻辑无关。JavaScript为单线程事件循环模型,findBook(title)返回的Promise属于异步任务,传入.then()的回调会被暂存到微任务队列,不会阻塞后续同步代码执行。
现有代码的实际执行顺序:
- 初始化变量
bookId,赋值为-1 - 调用
findBook发起书籍查询请求,将「给bookId赋值、打印bookId」的回调注册到微任务队列,代码直接向下执行,不会等待查询请求返回 - 同步拼接DELETE请求的API地址,此时
bookId仍为初始值-1 - 基于拼接好的、携带-1的地址发起DELETE请求
- 所有同步代码执行完毕后,事件循环才会处理微任务队列中的回调,此时才会将
bookId更新为查询到的4,但删除请求早已发出,无法拿到更新后的值。
你控制台中打印出4的时机晚于DELETE请求报错的时机,也能印证这个执行顺序。
修复方案
将所有依赖findBook返回结果的逻辑全部移入Promise链式调用中,确保拿到正确的bookId后再拼接地址、发起删除请求:
export function deleteBook(title: string): Promise<Book> { return findBook(title) .then((response) => { const bookId = Number(response[0].id); const API = `${apiURL}/api/books/${bookId}`; return axiosInstance.delete(API); }) .then((responseJson) => responseJson.data); }
如果使用async/await语法,逻辑会更直观,从根源上避免时序错乱问题:
export async function deleteBook(title: string): Promise<Book> { const response = await findBook(title); const bookId = Number(response[0].id); const API = `${apiURL}/api/books/${bookId}`; const responseJson = await axiosInstance.delete(API); return responseJson.data; }
优化提示
- 无需额外使用
Promise.resolve/Promise.reject包装返回值,axios调用本身就返回Promise,直接返回链式调用结果即可,冗余包装会增加不必要的代码量 - 做接口调用时建议增加异常捕获逻辑,比如查询不到对应书籍、删除权限不足等场景的错误提示

内容的提问来源于stack exchange,提问作者Ashar
相关产品推荐
相关产品推荐

