I just read about async functions
and found some similar features for ES2017. It's causing a lot of confusion and I just want to ask:
async function
, AsyncFunction
(used to create an async function), and an async function expression (which I think is just another async function)? Highlights of everyone's quirks and performances would be greatly appreciated!
P粉2877263082024-03-26 00:44:29
There are four ways to create functions in Javascript. There are also four ways to create asynchronous functions in Javascript, which are exact mirrors of each other.
To demonstrate how this works, I used 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 hoisted to the top of the current function scope.
Function declarations are exactly the same as async function declarations, except that async
functions always return a Promise and allow 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. However, they are not promoted to the top of the function scope. You can redefine them as many times as needed. They can be defined inline. They can be anonymous or named: if they are named, the name refers to a function within that function's scope.
Function expressions are exactly the same as async function expressions, except that async
functions always return a Promise and allow 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 equivalent in most respects 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 are exactly the same as async arrow functions, except that async
functions always return a Promise and allow you to use await
. (They are slightly different in the above statements because there are multiple statements inside each async function. This means that these statements need to be contained in a block {}
and return
Need to be explicit. This is also true for ordinary arrow functions longer than one statement.)
let speak = new Function('word', 'return "Hi " + word;'); let speak = new AsyncFunction('word', 'await sleep(1000); return "Hi " + word;')
The function constructor allows you to dynamically define functions using strings. Note that they always run in the global scope and have no access to the scope in which they are defined. They are only useful in rare circumstances. Personally I don't think an async function constructor would be useful. The author of ES2017 agrees with me, since AsyncFunction
is not a global object and must be obtained first using const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor
.
Functions created using the function constructor are exactly the same as functions created using the anonymous function constructor, except that the async
function always returns a Promise and allows you to use await
. (But you already guessed it, right?)