如何解决async箭头函数无法适配depromisify工具的问题?
解决Async箭头函数无法通过depromisify绑定this的问题
这个问题的核心在于箭头函数的本质特性:它不会创建自己的this上下文,而是继承自定义时所在的词法作用域。所以当你的depromisify尝试用fn.apply(this, args)调用async箭头函数时,箭头函数内部的this并不会被替换成调用时的this(也就是Usual的实例),自然会因为this.hello()找不到方法而报错。
方案1:改用普通Async函数(推荐)
最稳妥且符合JS设计意图的解决方案,就是把async箭头函数换成普通的async函数——普通函数允许动态绑定this,你的depromisify可以直接正常工作:
new Usual(depromisify(async function() { this.hello(); return false; }));
这样调用时,this会被正确绑定到Usual的实例,hello()方法也能正常执行。
方案2:修改depromisify适配箭头函数(hack式,不推荐生产环境)
如果你坚持要使用箭头函数的写法,可以通过一些hack手段将箭头函数转换为可绑定this的普通async函数。原理是将箭头函数的源码转换为普通函数的形式,再通过eval执行(注意:eval存在安全风险,且依赖函数toString()的输出格式,不同JS引擎可能有差异):
const depromisify = fn => { if (!(fn[Symbol.toStringTag] === 'AsyncFunction')) { return fn; } // 处理箭头函数,转换为普通async函数 let fnStr = fn.toString(); // 匹配带参数的async箭头函数格式,替换为普通async函数 fnStr = fnStr.replace(/^async\s*\((.*?)\)\s*=>/, 'async function($1)'); // 处理无参数的async箭头函数格式 fnStr = fnStr.replace(/^async\s*=>/, 'async function()'); // 生成可绑定this的普通async函数 const boundAsyncFn = eval(`(${fnStr})`); return function () { const args = [...arguments]; const cb = args.pop(); (async () => { try { const result = await boundAsyncFn.apply(this, args); cb(null, result); } catch (e) { cb(e); } })(); }; }; // 现在可以正常使用async箭头函数了 new Usual(depromisify(async () => { this.hello(); return false; }));
注意事项:
- 这个方法依赖函数的
toString()输出,某些压缩后的代码或者特殊环境下可能失效。 eval会执行字符串代码,若函数来源不可信,存在XSS或代码注入风险,生产环境谨慎使用。
为什么箭头函数不能绑定this?
ECMAScript规范中,箭头函数被设计为无this绑定的函数,它的this永远指向定义时所在的外层作用域的this,任何试图通过call/apply/bind修改箭头函数this的操作都会被忽略。这也是箭头函数不适合作为需要动态this的回调函数的原因。
内容的提问来源于stack exchange,提问作者Misiur
相关产品推荐
相关产品推荐

