useEffect钩子中回调转async/await报错:局部作用域与this指向问题解决
回调风格API转async/await时的this指向问题
原可正常运行的代码
useEffect(() => { const apiService = new APIClient('api address'); var topicCommentsReq = new GetTopicDetailsRequest(); topicCommentsReq.setTopicCid(Buffer.from("123", "hex")); apiService.getTopicDetails(topicCommentsReq, {}, function (err, response) { console.log(`response : ${JSON.stringify(response)}`); }); }
转换后的async/await代码(出现错误)
const promisifyFn = (fn: Function) => (...args: any[]) => new Promise((resolve, reject) => { return fn(...args, (err: Error, data: any) => { return err ? reject(err) : resolve(data); }); }); useEffect(() => { (async () => { const apiService = new APIClient("api address"); const topicCommentsReq = new GetTopicDetailsRequest(); topicCommentsReq.setTopicCid(Buffer.from("123", "hex")); const getTopicDetails = promisifyFn(apiService.getTopicDetails); try { const res = await getTopicDetails(topicCommentsReq, {}); console.log(`response : ${JSON.stringify(res)}`); } catch (e) { console.log(e); } })(); });
错误信息
TypeError: Cannot read properties of undefined (reading 'client_') if (callback !== undefined) { return this.client_.rpcCall( this.hostname_ + '/StelaPlatform.GRPC.API/GetTopicDetails', request, metadata || {}, this.methodDescriptorGetTopicDetails, callback); }
问题原因
将apiService.getTopicDetails作为参数传给promisifyFn时,方法的this绑定丢失——调用提取后的getTopicDetails时,this不再指向apiService实例,导致内部无法访问this.client_等属性。
通用解决方案
方案1:修改promisifyFn,支持传入上下文
让promisify函数接收可选的上下文参数,调用原方法时用call绑定该上下文:
const promisifyFn = (fn: Function, thisArg?: any) => (...args: any[]) => new Promise((resolve, reject) => { fn.call(thisArg, ...args, (err: Error, data: any) => { err ? reject(err) : resolve(data); }); }); // 使用时传入apiService作为上下文 const getTopicDetails = promisifyFn(apiService.getTopicDetails, apiService);
方案2:提取方法时用bind绑定this
直接在提取方法时,用bind把this固定为apiService实例:
const getTopicDetails = promisifyFn(apiService.getTopicDetails.bind(apiService));
方案3:用箭头函数包装原方法
箭头函数会继承当前作用域的上下文,用它包装原方法调用,保留apiService的绑定关系:
const getTopicDetails = promisifyFn((...args) => apiService.getTopicDetails(...args));
三种方案均能解决this指向问题,其中方案1通用性最强,适合批量处理多个实例方法的场景。
内容的提问来源于stack exchange,提问作者Chuang Fu
相关产品推荐
相关产品推荐

