JS循环中使用await会产生什么“化学反应”

1. 先简单了解一下什么是async/await

在深入讲解JS循环中使用await会产生什么“化学反应”之前,我们先来梳理一下async/await的相关知识点。

async/await是ES7(ES2017)中引入的新特性,它是Promise的语法糖,使得异步代码看起来更像同步代码。

async函数是返回一个Promise对象的函数,它会自动将普通函数转为Promise对象,然后在函数体内部使用await来等待Promise对象的处理结果。

比如下面的awaitson函数,返回Promise对象

async function awaitson() {

return 1;

}

console.log(awaitson()); // Promise {: 1}

接下来,我们看一下async/await在使用上的注意事项:

async函数必须包含await语句。

await必须在async函数中使用。

await后面可以跟Promise对象或者普通值,如果是普通值则自动包装为一个Promise对象。

如果Promise对象没有被resolve,则async函数会停止执行。

如果Promise对象被reject了,async函数会抛出异常。

那么async/await是如何实现异步操作的呢?其实,它是将异步调用转换为类似同步代码的写法,例如执行await语句时,会阻塞代码执行,直到Promise对象被resolve或reject。

2. 循环中使用await会发生什么

2.1 使用await in for循环

在for循环中使用async/await,我们需要注意两个细节:

Promise对象在await之前需要先执行完成才会执行下一次循环。

由于循环异步进行,遇到await后会暂停执行,所以循环中的异步操作并非按序执行,可能会导致一些bug。

详细代码说明如下:

async function allFunc() {

const arr = [1, 2, 3, 4, 5];

for (let i = 0; i < arr.length; i++) {

const result = await fetch(`https://jsonplaceholder.typicode.com/todos/${arr[i]}`);

console.log(`异步获取数据${arr[i]}: `, await result.json()); // 数据调用

}

console.log('操作完成');

}

allFunc();

程序执行结果如下:

异步获取数据1: {userId: 1, id: 1, title: "delectus aut autem", completed: false}

异步获取数据2: {userId: 1, id: 2, title: "quis ut nam facilis et officia qui", completed: false}

异步获取数据3: {userId: 1, id: 3, title: "fugiat veniam minus", completed: false}

异步获取数据4: {userId: 1, id: 4, title: "et porro tempora", completed: true}

异步获取数据5: {userId: 1, id: 5, title: "laboriosam mollitia et enim quasi adipisci quia provident illum", completed: false}

操作完成

从执行结果来看,Promise会按顺序执行,并且所有异步操作完成后,才会执行后续代码。

2.2 使用await in forEach循环

forEach循环中,我们不能使用await来暂停代码执行,因为它不会等待异步操作完成就会进行下一次遍历。

对forEach和普通for循环的比较,详见下方代码:

//使用forEach循环获取数据

async function forEachFunc () {

const arr = [1, 2, 3, 4, 5];

arr.forEach(async (item) => {

const result = await fetch(`https://jsonplaceholder.typicode.com/todos/${item}`);

console.log('异步获取的结果', await result.json()); // undefined

});

console.log('操作完成');

}

forEachFunc();

//使用普通for循环获取数据

async function forFunc() {

const arr = [1, 2, 3, 4, 5];

for(let i = 0; i < arr.length; i++) {

const result = await fetch(`https://jsonplaceholder.typicode.com/todos/${arr[i]}`);

console.log('异步获取的结果', await result.json()); // 数据调用

if(i === arr.length - 1) {

console.log('操作完成');

}

}

}

forFunc();

代码执行结果如下:

异步获取的结果 undefined

异步获取的结果 { userId: 1, id: 1, title: 'delectus aut autem', completed: false }

异步获取的结果 { userId: 1, id: 2, title: 'quis ut nam facilis et officia qui', completed: false }

异步获取的结果 { userId: 1, id: 3, title: 'fugiat veniam minus', completed: false }

异步获取的结果 { userId: 1, id: 4, title: 'et porro tempora', completed: true }

异步获取的结果 { userId: 1, id: 5, title: 'laboriosam mollitia et enim quasi adipisci quia provident illum', completed: false }

操作完成

异步获取的结果 { userId: 1, id: 1, title: 'delectus aut autem', completed: false }

异步获取的结果 { userId: 1, id: 2, title: 'quis ut nam facilis et officia qui', completed: false }

异步获取的结果 { userId: 1, id: 3, title: 'fugiat veniam minus', completed: false }

异步获取的结果 { userId: 1, id: 4, title: 'et porro tempora', completed: true }

异步获取的结果 { userId: 1, id: 5, title: 'laboriosam mollitia et enim quasi adipisci quia provident illum', completed: false }

操作完成

从结果可以看出,使用forEach循环获取异步数据时,会执行所有的异步操作,最后才会输出“操作完成”,说明循环遍历是异步进行的,没有等待异步操作完成。

而在使用for循环获取数据时,所有的console.log()都等到了异步获取数据后才会输出,说明循环遍历是同步进行的。

2.3 await出现在函数中return之后

await出现在函数中return之后,会直接返回一个Promise对象。

async function asyncFunc () {

await 'async';

return 'return';

}

console.log(asyncFunc());

执行结果如下:Promise {}

为何会这样?因为async/await语法糖本身就是Promise的语法糖,async就是返回一个Promise对象,而在函数中使用await是等待Promise,所以这个Promise对象一直是pending状态。

3. 建议和总结

3.1 建议

对于单个请求,我们可以使用async/await方法来实现。

对于多个请求,使用Promise.all([])可以实现并行异步操作。

当我们处理多个异步操作,而这些操作需要先后顺序时,这时就需要使用Promise来实现异步操作。

3.2 总结

在ES7之前,我们常使用回调函数或Promise进行异步操作处理。但是这种方式还是太难维护、扩展,迭代成本高等问题限制了异步操作的发展。而ES7新引入的async/await,使代码简洁、易懂。同时,async/await等语法糖也能够使代码执行时更直观地表达出异步与同步的关系。但在使用它时,还是有一些需要注意的地方,比如循环中使用await等问题。因此,在使用async/await进行异步操作时,开发者应该对其进行深入了解,并在实际项目中进行规范的使用。

目前,JS异步编程掌握async/await应该足以提升我们的实际编码能力。接下来,我们可以结合Promise等其他技术来实践更复杂的业务场景。这样可以更好地掌握JS异步编程,进一步提升自我在JS开发中的技术水平和团队开发的效率。

免责声明:本文来自互联网,本站所有信息(包括但不限于文字、视频、音频、数据及图表),不保证该信息的准确性、真实性、完整性、有效性、及时性、原创性等,版权归属于原作者,如无意侵犯媒体或个人知识产权,请来电或致函告之,本站将在第一时间处理。猿码集站发布此文目的在于促进信息交流,此文观点与本站立场无关,不承担任何责任。