I was just reading about async functions
and came across some similar features of ES2017. It has created a lot of confusion, I wanted to just ask:
async function
, AsyncFunction
(which is used to create an async function), and an async fuction expression (which is what I think just another async function)?Highlights on the quirks and performance of each would be appreciated!
The word “async” before a function means one simple thing: a function always returns a promise. Other values are wrapped in a resolved promise automatically. So, async ensures that the function returns a promise, and wraps non-promises in it.
The executor function can also be an async function . However, this is usually a mistake, for a few reasons: If an async executor function throws an error, the error will be lost and won't cause the newly-constructed Promise to reject. This could make it difficult to debug and handle some errors.
Async/await and then() are very similar. The difference is that in an async function, JavaScript will pause the function execution until the promise settles. With then() , the rest of the function will continue to execute but JavaScript won't execute the . then() callback until the promise settles.
Async/Await is used to work with promises in asynchronous functions. It is basically syntactic sugar for promises. It is just a wrapper to restyle code and make promises easier to read and use. It makes asynchronous code look more like synchronous/procedural code, which is easier to understand.
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 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
.
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
.
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.)
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?)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With