Lodash _.functions and Asynchronous Class Methods

Lodash's _.functions method retrieves an array of function property names from an object, but it does not differentiate between strictly synchronous methods and asynchronous class methods. Internally, Lodash evaluates all callable objects using its standard type-checking utility, treating both standard functions and AsyncFunction instances identically while relying strictly on property enumeration rather than function execution traits.

Internal Function Identification

Lodash implements _.functions by iterating over an object’s own enumerable properties and filtering them with an internal check, primarily isFunction.

In modern JavaScript engines, an asynchronous function is an instance of the hidden AsyncFunction constructor. However, AsyncFunction.prototype inherits from Function.prototype, and calling typeof on an async method evaluates to "function". Lodash's internal baseGetTag method inspects the [[Class]] tag via Object.prototype.toString.call(value). Lodash explicitly includes tags like [object Function], [object AsyncFunction], [object GeneratorFunction], and [object Proxy] as valid functions. Because both synchronous and asynchronous functions pass this predicate, _.functions groups them together without distinction.

The Role of Class Method Enumerability

When working specifically with ES6 class methods, developers often encounter an additional layer of behavior: property enumerability.

  1. Standard Class Methods: Methods defined directly in a class body (whether declared with async or not) are placed on the class's prototype and are set to enumerable: false by default. Because _.functions only inspects an object’s own enumerable properties using mechanisms similar to Object.keys, it will not extract traditional class methods—synchronous or asynchronous—from class instances unless _.functionsIn is used or the prototype is inspected directly.
  2. Public Class Field Methods: If methods are defined as arrow functions or bound fields (e.g., syncMethod = () => {} or asyncMethod = async () => {}), they are assigned directly to the instance as own enumerable properties. In this case, _.functions detects both.

How to Manually Differentiate Sync and Async Methods

Because _.functions deliberately does not segregate functions based on their return type or execution mechanism, separating them requires custom JavaScript inspection using runtime metadata.

To identify strictly asynchronous methods, you must inspect the function constructor or its string tag:

const isAsync = (fn) => fn[Symbol.toStringTag] === 'AsyncFunction' || fn.constructor.name === 'AsyncFunction';

Alternatively, synchronous methods that return a Promise at runtime cannot be identified prior to execution without analyzing the returned value via value instanceof Promise or checking for a then method. Lodash avoids this level of runtime introspection, maintaining _.functions as a structural property lister rather than a method signature analyzer.