ES 2017: async function vs AsyncFunction(object) vs async function expression ES 2017:async函数 vs AsyncFunction(对象)vs异步函数表达式

7
我刚刚在阅读有关异步函数的内容时,发现了ES2017的一些类似功能。这引起了很多混淆,我想问一下:
  1. async functionAsyncFunction(用于创建异步函数)和异步函数表达式(我认为只是另一个异步函数)之间有什么区别?
  2. 在什么情况下应该使用其中一种格式?
希望能突出每个格式的特点和性能!

4
functionFunction(对象)和函数表达式相同,唯一的区别是该函数是async - Jaromanda X
1
有关编程的内容,将以下文本从英语翻译成中文。仅返回已翻译的文本:除了异步行为之外,还有什么不同吗? - Syed Huzaifa Hassan
1
我并没有说两者没有任何不同...我是说异步风格和“标准”风格之间的差异是相同的...所以,1、2、3不同于4、5、6,但1和2和3之间的差异与4和5和6之间的差异是相同的 :p - Jaromanda X
1
是的,我明白了,我的意思是functionFunction(对象)和function expression中的差异是相同的吗?我仍然很好奇是否还有其他不同之处。 - Syed Huzaifa Hassan
1个回答

13

在Javascript中创建函数的方法有四种。同样,在Javascript中创建异步函数的方式也有四种,它们是彼此精确镜像。

为了演示如何工作,我使用了一个简单的全局声明的sleep函数:

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'; }

这是声明函数最简单的方法。它只能声明一次,并被提升到当前函数作用域的顶部。

函数声明和异步函数声明完全相同,除了async函数始终返回promise并允许您使用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

函数表达式看起来很像函数声明,但是它们不会被提升到函数作用域的顶部。你可以重新定义它们多次。它们可以在内联中定义。它们可以是匿名的,也可以是命名的:如果它们是命名的,则该名称在该函数的作用域内引用该函数。

函数表达式和异步函数表达式完全相同,只是async函数始终返回一个 Promise,并允许你使用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

箭头函数是一种快速简洁的定义函数的方式,引入自ES2015(ES6)。它们在大多数方面与函数表达式等价,唯一的区别是箭头函数始终是匿名的且this的值总是词法绑定的,即从外部作用域继承而来。

箭头函数和异步箭头函数完全相同,只是async函数始终返回一个promise并允许使用await。(它们在上述语句中略有不同,因为异步函数中每个语句都有不止一个,这意味着需要将语句包含在一个块中{}并且return需要明确指出。对于多于一个语句的普通箭头函数也是如此。)

函数构造器

let speak = new Function('word', 'return "Hi " + word;');
let speak = new AsyncFunction('word', 'await sleep(1000); return "Hi " + word;')

通过使用字符串,函数构造函数允许您动态定义函数。请注意,它们始终在全局范围内运行,并且无法访问它们定义的范围。它们仅在非常少量的情况下有用。我个人认为,异步函数构造函数永远不会是一个有用的东西。ES2017的编写者也同意我的看法,因为AsyncFunction不是全局对象,并且必须先使用const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor获得。

使用函数构造函数创建的函数和使用匿名函数构造函数创建的函数完全相同,除了async函数始终返回一个promise并允许您使用await。(但您已经猜到了吧?)


我会删除语句“函数表达式在大多数情况下与函数声明相同”,但除此之外我会+1。 - Bergi
@Bergi 内部语法相同;它们以相同的方式被调用;它们可以以相同的方式传递……与 PHP 中相应语法相比,它们更加相似。 - lonesomeday
2
语法看起来很相似,但是你不能直接调用或传递函数声明,必须使用名称。相反,你不能使用函数表达式的名称,需要对表达式的结果进行操作。 - Bergi
@Bergi 为了绝对的清晰度,我稍微编辑了我的答案。感谢您的评论。 - lonesomeday

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接