如何在React中使用AbortController取消Promise?实现异常问题求助
问题原因及修复方案
你的代码存在4个核心错误,逐一排查修复即可:
- 变量名引用错误,导致signal和controller不匹配
- Promise状态提前敲定,abort监听逻辑失效
- React重渲染时AbortController实例被重置,前后实例不统一
- 同步循环没有加中断检查,无法响应中途的abort操作
1. 修复变量名&稳定AbortController实例
WrapperComponent.tsx中你声明的实例名是controller,但获取signal时用了不存在的abortController,同时要使用useRef保存实例避免重渲染时生成新实例:
import { useRef } from 'react' export const WrapperComponent = () => { // 用useRef保证controller实例永远不变 const controllerRef = useRef(new AbortController()); const doSomeStuff = (file: any): void => { // 每次调用前先重置实例,避免之前的abort状态影响新请求 controllerRef.current = new AbortController(); const signal = controllerRef.current.signal; calculateSomeStuff(signal, file) .then((hash) => { // 执行相关逻辑 }) .catch((error) => { if (error.name === 'AbortError') { // 处理取消逻辑 return } // 处理其他错误 }); }; return (<Table controller={controllerRef.current} />) }
2. 修复calculateSomeStuff逻辑
你需要先绑定abort监听,再执行业务逻辑,同时不要提前resolve Promise,同步循环内要加中断判断:
export const calculateSomeStuff = async (signal, file): Promise<any> => { // 先判断是否已经被取消 if (signal.aborted) { console.log('signal.aborted', signal.aborted); throw new DOMException('Aborted', 'AbortError'); } return new Promise((resolve, reject) => { // 先绑定abort监听 const abortHandler = () => { console.log('Aborted'); reject(new DOMException('Aborted', 'AbortError')); }; signal.addEventListener('abort', abortHandler); try { // 同步循环内加中断判断 for (let i = 0; i <= 10; i++) { if (signal.aborted) return; // 执行相关逻辑 } const secret = 'ojefbgwovwevwrf'; console.log('Promise Started'); resolve(secret); } catch (err) { reject(err); } finally { // 执行完成后移除监听避免内存泄漏 signal.removeEventListener('abort', abortHandler); } }); };
3. Table组件可选优化
你定义的handleAbort接收的fileName参数没有用到,可以按需删除,本身逻辑没有错误:
export const Table = ({controller}) => { const handleAbort = () => { controller.abort(); }; return ( <Button onClick={handleAbort} /> ); }
内容的提问来源于stack exchange,提问作者Codehan25
相关产品推荐
相关产品推荐

