JavaScript 比较使用Async/Await和生成器实现相同功能
异步编程在现代Web开发中变得越来越重要,因为它允许更有效地使用资源,并可以提供更好的用户体验。在JavaScript中,两种流行的异步编程方法是async/await和生成器。虽然这两种方法都有各自的优点和缺点,但在某些情况下它们可以用来实现类似的功能。在本文中,我们将比较async/await和生成器,并强调它们在各个方面的差异和相似之处。
JavaScript中的异步: JavaScript中的异步指的是异步编程,它是一种允许程序同时执行多个任务的技术,而不是按照线性顺序进行。异步代码允许程序在等待长时间运行的任务完成时继续运行并响应其他请求或事件,而不会阻塞主线程。这导致应用程序更高效和响应,特别是在处理网络请求或其他I/O操作时。
JavaScript使用回调函数、Promise和async/await来处理异步代码,这对于处理需要大量时间加载的API或其他资源特别有用。
语法:
async function functionName(parameter1, parameter2, ...) {
// function body
}
您还可以使用箭头函数来定义一个异步函数,如下所示:
const functionName = async (parameter1, parameter2, ...) => {
// function body
}
示例:
JavaScript
async function fun() {
return 7;
}
fun().then(result => console.log(result));
输出:
7
异步函数总是返回一个promise。其他值会自动包装在一个promise中,所以async确保函数返回一个promise并将非promise包装其中。该函数将返回一个已解析的promise,其结果为7。
JavaScript中的Await: “Await”在JavaScript中是一个语言特性,它在ES2017(ECMAScript 2017)中被引入,允许开发人员以类似同步编程的方式编写异步代码。Await只能在“async”函数内部使用,并且它会暂停函数的执行,直到Promise被解析。这使得开发人员可以避免使用回调函数和“回调地狱”,而是编写更像是顺序、阻塞代码的代码。
语法:
const result = await promise;
示例 1:
JavaScript
function wait(delay) {
return new Promise(resolve => setTimeout(resolve, delay));
}
async function printMessage(message, delay) {
await wait(delay);
console.log(message);
}
printMessage("Hello", 1000);
输出:
Hello
说明: 在这个例子中,wait函数返回一个在指定延迟后解析的promise对象。printMessage函数接受一个消息和一个延迟作为参数,并在等待指定延迟后将消息记录到控制台中。使用await关键字暂停printMessage函数的执行,直到wait promise对象解析。这确保消息只有在指定延迟后记录到控制台中。当调用printMessage(“Hello”,1000)时,它在等待1秒后将字符串“Hello”记录到控制台中。
例子2:
JavaScript
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// Expected output: "calling" "resolved"
}
asyncCall();
输出:
Calling
Resolved
解释: 在上面的例子中,我们定义了一个函数resolveAfter2Seconds,它返回一个延迟2秒后解析的Promise。Promise构造函数接受一个定义如何解析Promise的函数。在这种情况下,我们定义了一个回调函数,在2秒延迟后调用resolve。我们定义了一个async函数asyncCall,它在控制台记录“calling”,使用await关键字等待resolveAfter2Seconds Promise解析,并将解析后的值记录到控制台。
Javascript中的生成器: 生成器函数是ES6版本中引入的一种函数类型。与普通函数不同,生成器允许其他代码多次进入和退出。当生成器函数遇到“yield”表达式时,它暂停执行,直到从外部源接收到继续执行的指令。
生成器和普通函数之间最重要的区别之一是,在执行过程中生成器可以产生多个值。它们不会一次生成所有值,而是根据需要逐个生成值序列。当请求值时,生成器函数提供值,直到达到执行的末尾。此时,“done”标志设置为true,表示生成器已完成其任务。
语法:
function* myGenerator(){
//code
}
示例:
Javascript
function* fibonacci() {
let a = 0;
let b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacci();
console.log(fib.next().value); // 0
console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2
console.log(fib.next().value); // 3
console.log(fib.next().value); // 5
输出:
0
1
1
2
3
5
解释: fibonacci()函数是一个生成器函数,它生成一个无穷的斐波那契数列。当调用fibonacci()函数时,它返回一个生成器对象。while循环内的yield关键字暂停函数的执行并返回a的当前值。下一次调用生成器对象的next()方法时,函数继续执行从上次暂停的地方,并计算下一个斐波那契数。
Async/Await和Generators之间的比较:
方面 | Async/Await | Generators |
---|---|---|
定义 | JavaScript中一组关键字,允许以同步的方式编写异步操作。 | 一种特殊类型的函数,可以暂停执行并随时间返回多个值。 |
执行 | 顺序执行并可以暂停当前函数的执行,直到等待的promise被解析。 | 惰性执行,可以使用yield关键字暂停和恢复执行。 |
语法 | 使用async关键字定义异步函数,await关键字等待promise解析。 | 使用function*定义生成器函数,使用yield暂停和恢复执行。 |
错误处理 | 使用try / catch处理错误。 | 使用try/catch和.throw()方法的组合来处理错误。 |
多个值 | 只能返回一个值(或解析为单个值的promise)。 | 可以使用yield随时间返回多个值。 |
迭代 | 不能用于迭代。 | 可以使用‘for…of’循环进行迭代。 |
兼容性 | 需要支持async/await的现代JavaScript运行时。 | 可以在支持ES6生成器的旧JavaScript运行时中使用。 |
用例 | 最适合涉及进行多个异步请求并需要等待每个请求完成后才能继续的任务。 | 最适合涉及随时间生成多个值的任务,例如解析大型数据集或创建无限序列。 |
总之,Async/Await和Generators各有优缺点,但在JavaScript中处理异步操作时,Async/Await是更现代且更易于使用的选择。如果您正在开始一个新项目或希望编写可读性和可维护性的异步代码,Async/Await是更好的选择。