类成员函数中使用async.series时无法访问this引用与类成员的解决方法
问题根因
传入async.series的普通function回调的this值由调用方的执行上下文决定。async模块内部调度执行这些回调时,不会继承类成员方法f的执行上下文,因此回调内部的this不会指向类实例,最终触发访问不到member属性的类型错误。
可行解决方案
所有方案的核心都是让async.series流程块内的代码能够稳定获取类实例的引用,从根源上避免上下文丢失的问题。
方案1:使用箭头函数定义流程回调*(最推荐)*
箭头函数没有独立的this绑定,会捕获定义时所在词法环境的this,也就是类方法f被调用时指向的类实例,不需要额外的绑定逻辑,代码最简洁。
修改后的可运行代码:
const async = require("async"); class X { constructor() { this.member = 1; } f(){ async.series([ (cb) => { console.log('s1') cb(); }, (cb) => { console.log('s2') console.log(this.member) // 可正常访问实例成员,输出1 cb(); } ], () => { console.log('here') }); } } (new X()).f()
实际运行输出:
s1 s2 1 here
方案2:提前缓存类实例引用(兼容老旧环境)
如果项目需要兼容不支持箭头函数的老旧JS运行环境,可以在类方法内部把当前类实例的引用缓存为固定变量,在所有回调内部直接引用这个缓存变量,不依赖回调自身的this绑定。
示例代码:
const async = require("async"); class X { constructor() { this.member = 1; } f(){ const self = this; // 缓存当前类实例引用 async.series([ function (cb) { console.log('s1') cb(); }, function (cb) { console.log('s2') console.log(self.member) // 直接引用缓存的实例变量 cb(); } ], function(){ console.log('here') }); } } (new X()).f()
方案3:手动绑定回调的执行上下文
可以使用Function.prototype.bind()方法,在把回调传入async.series时,主动把类实例绑定为回调的this值,不需要修改回调内部的逻辑。
示例代码:
const async = require("async"); class X { constructor() { this.member = 1; } f(){ async.series([ function (cb) { console.log('s1') cb(); }.bind(this), // 逐个绑定类实例为回调的this function (cb) { console.log('s2') console.log(this.member) cb(); }.bind(this) ], function(){ console.log('here') }.bind(this)); } } (new X()).f()
这个方案写法相对冗余,长流程下需要给每个回调单独做绑定,维护成本稍高。
补充提示:如果流程中的执行步骤是抽离为类的独立成员方法,在传入
async.series数组时,必须同样通过.bind(this)或者箭头函数包裹的方式绑定类实例上下文,否则依然会出现this丢失的问题,示例:f(){ async.series([ // 箭头函数包裹抽离的类方法,自动绑定this (cb) => this.step1(cb), (cb) => this.step2(cb) ], () => { console.log('here') }); }
内容的提问来源于stack exchange,提问作者Ulysses
相关产品推荐
相关产品推荐

