In JavaScript you can create a function by using the Function constructor:


const sum = new Function('return Array.from(arguments).reduce(function(a,b){return a+b})');

The above code produces a sum() function which takes 1 or more arguments and returns the sum of them all added together. You can check out the following to see this in action:

What About AsyncFunction()?

You may have noticed that although globalThis.Function is easily accessible, globalThis.AsyncFunction doesn’t exist (at least not at the time of publishing this post). What can we do to get access to it then? Easy peasy lemon squeezy:


const AsyncFunction = (async x=>x).constructor;

Now we can use it to make our own asynchronous functions from strings:

// <!--
// Define the AsyncFunction constructor.
const AsyncFunction = (async x=>x).constructor;

/**
* Creates an asynchronous function which returns a `Date` object after waiting
* the specified number of sections.
* @param {number} waitInSecs
* Number of seconds to wait before returning a `Date` object for the time at
* the point of return.
* @return {Date}
* The time after waiting the specified number of seconds.
*/
const waitForDate = new AsyncFunction(
'waitInSecs',
`
return await new Promise(
(resolve, reject) => setTimeout(() => resolve(new Date), waitInSecs * 1000)
);
`
);

// Get the current date/time.
console.log(new Date);
// Wait 3 seconds and then get the date/time again.
console.log(await waitForDate(3));
// -->

Testing A Function To See If It Is Asynchronous

Testing a function to see if it is asynchronous can be done at least two different ways:

  1. You can access the constructor’s name:

    
    function isAsyncFunction(value) {
      return value?.constructor?.name === 'AsyncFunction';
    }
    

    This option should work as long as you know that the global namespace has not been tampered with so as to possible change the name of the constructors.

  2. You can access the constructor’s name:

    
    const isAsyncFunction = (function(af) {
      return function(value) {
        return af.constructor === value?.constructor;
      };
    })(async x=>x);
    

    This option should work as long as you are only testing values from within the same window or environment. In other words, this will not work if you test a value from an IFRAME because the constructor will be different.

  3. You can use Object.prototype.toString to get the name:

    
    function isAsyncFunction(value) {
      return Object.prototype.toString.call(value).slice(8, -1) === 'AsyncFunction';
    }
    

    This option should work in all cases but will be slightly less efficient than the other options because it is making 2 additional function calls.

It is important to note that using typeof will indicate that an asynchronous function is indeed a function but it doesn’t help you differentiate the two:

Final Thoughts

There are plenty reasons why you want to be extra careful when creating functions from strings (eg. security) but if you know what you are doing the Function constructor and the AsyncFunction constructor can be very useful. Let me know what you think and as always, happy coding!


Leave a Reply

Your email address will not be published. Required fields are marked *