如何在NodeJS中检测函数是否为async类型?
如何在NodeJS中区分普通函数与异步函数?
在浏览器中检测一个函数是否为async类型很简单,但在NodeJS里,通过constructor.name或原型对比的方式却无法区分,比如运行以下代码:
console.log({ // 浏览器中为'Function',NodeJS中为空字符串('') '(() => {}).constructor.name': (() => {}).constructor.name, '(async () => {}).__proto__.constructor.name': (async () => {}).__proto__.constructor.name, // 浏览器中为'AsyncFunction',NodeJS中为空字符串('') '(async () => {}).constructor.name': (async () => {}).constructor.name, '(async () => {}).__proto__.constructor.name': (async () => {}).__proto__.constructor.name, // 浏览器中返回false,NodeJS中返回true '(async () => {}).constructor === (() => {}).constructor': (async () => {}).constructor === (() => {}).constructor, '(async () => {}).__proto__ === (() => {}).__proto__': (async () => {}).__proto__ === (() => {}).__proto__, '(async () => {}).__proto__.constructor === (() => {}).__proto__.constructor': (async () => {}).__proto__.constructor === (() => {}).__proto__.constructor, });
我需要区分两者的原因是:希望在给函数添加包装代码时保留原函数的签名。如果通过Promise.resolve把所有函数都转成接受thenable对象的形式,多数函数调用都要改成async方法(或期望async thenable),但这在NodeJS(或React Native)中会有问题——因为它们严格遵循Promises/A+规范,随意把所有函数转为async会改变原有代码的功能。
可行的检测方法
方法1:通过instanceof判断构造函数关联
NodeJS中虽然AsyncFunction的name属性为空,但构造函数的引用是唯一且可获取的,我们可以通过实例关系来判断:
// 获取AsyncFunction的构造函数引用 const AsyncFunction = (async () => {}).constructor; function isAsyncFunction(fn) { // 先判断是否为函数,再检测是否是AsyncFunction的实例 return typeof fn === 'function' && fn instanceof AsyncFunction; }
这个方法可靠性高,不受代码压缩的影响,是优先推荐的方案。
方法2:通过函数的toString()特征判断
async函数的toString()输出会以async 开头,普通函数则不会,利用这个特征可以做检测:
function isAsyncFunction(fn) { if (typeof fn !== 'function') return false; // 取函数字符串的前6位判断是否为'async ' return fn.toString().slice(0, 6) === 'async '; }
注意:如果代码经过了压缩混淆(比如把async关键字压缩掉),这个方法会失效,适合开发环境或未压缩的生产代码使用。
临时解决思路
如果暂时无法准确检测,也可以在包装函数时做兼容处理:
- 若原函数返回Promise(包括async函数),直接对其返回值做包装
- 若原函数是普通函数,仅在需要时用
Promise.resolve包裹返回值,而非强制把整个函数转为async,避免破坏原有同步逻辑
内容的提问来源于stack exchange,提问作者Steven
相关产品推荐
相关产品推荐

