There are four ways to create a function in Javascript. There are also four ways to create an asynchronous function in Javascript, and they are precise mirrors of each other.
To demonstrate how this works, I'm using a simple sleep
function, declared globally:
function sleep(time) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, time);
});
}
Function declarations
function speak() { return 'Hi'; }
async function speak() { await sleep(1000); return 'Hi'; }
This is the simplest way to declare a function. It can be declared once and is hoisted to the top of the current function scope.
Function declarations and asynchronous function declarations are exactly identical, except that the async
function always returns a promise and allows you to use await
.
Function expressions
let speak = function() { return 'Hi'; } // anonymous function expression
let speak = function speakFn() { return 'Hi'; } // named function expression
let speak = async function() { await sleep(1000); return 'Hi'; } // anonymous asynchronous function expression
let speak = async function speakFn() { await sleep(1000); return 'Hi'; } // named asynchronous function expression
Function expressions look very much like function declarations. They are not, however, hoisted to the top of the function scope. They can be redefined as many times as you like. They can be defined inline. They can either be anonymous or named: if they are named, then the name refers to the function within the scope of that function.
Function expressions and asynchronous function expressions are exactly identical, except that the async
function always returns a promise and allows you to use await
.
Arrow functions
let speak = word => 'Hi ' + word; // one parameter
let speak = (word1, word2) => 'Hi ' + word1 + word2; // multiple parameters
let speak = async word => { await sleep(1000); return 'Hi ' + word; } // one parameter
let speak = async (word1, word2) => { await sleep(1000); return 'Hi ' + word1 + word2; } // multiple parameters
Arrow functions are a quick and short way to define a function, introduced in ES2015 (ES6). They are in most ways equivalent to function expressions, except that they are always anonymous and the value of this
is always lexically bound, i.e. inherited from the outer scope.
Arrow functions and asynchronous arrow functions are exactly identical, except that the async
function always returns a promise and allows you to use await
. (They are slightly different in the statements above because the asynchronous functions each have more than one statement within them. This means that the statements need to be enclosed in a block {}
and the return
needs to be explicit. This is also true of normal arrow functions that are more than one statement long.)
Function constructors
let speak = new Function('word', 'return "Hi " + word;');
let speak = new AsyncFunction('word', 'await sleep(1000); return "Hi " + word;')
Function constructors allow you to define a function dynamically by using strings. Note that they are always run in the global scope and have no access to the scope in which they were defined. They are only useful in a very small set of circumstances. I personally can't see how an asynchronous function constructor would ever be a useful thing. The writers of ES2017 agree with me, as AsyncFunction
is not a global object and must be obtained first with const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor
.
Functions created with the function constructor and functions created with the anonymous function constructor are exactly identical, except that the async
function always returns a promise and allows you to use await
. (But you'd already guessed that, right?)
function
vsFunction
(object) vsfunction expression
- except the function isasync
– Alecaleciafunction
,Function
(Object) andfunction expression
? I am still curious if something else is different. – Connection