-
Notifications
You must be signed in to change notification settings - Fork 15
Open
@spivet
Description
async/await 基础
比起回调函数那看不懂的嵌套,Promise 要清爽不少,但当任务较多时, Promise 也有可能会有比较长的链和嵌套,这时候使用 async/await 就会让代码易读很多。
async
async 函数可以看作是 Promise 的语法糖:
// resolve 状态 async function foo() { console.log('start') return 'resolve' } foo().then(data => { console.log('data:', data) }) console.log('end') // start // end // data: resolve // reject状态 async function foo() { console.log('start') throw new Error('reject') } foo().catch(data => { console.log('data:', data.message) }) console.log('end') // start // end // data: reject
与下面直接使用 Promise 方式书写的效果一模一样:
// resolve 状态 function foo() { return new Promise((resolve, reject) => { console.log('start') resolve('resolve') }) } foo().then(data => { console.log('data:', data) }) console.log('end') // start // end // data: resolve // reject状态 function foo() { return new Promise((resolve, reject) => { console.log('start') reject('reject') }) } foo().catch(data => { console.log('data:', data) }) console.log('end') // start // end // data: reject
await
await 与其字面意思一样——等待,等待其后的函数执行完毕。
// resolve状态 async function foo() { console.log('start') return 'resolve' } async function bar() { const data = await foo() console.log('data', data) } bar() console.log('end') // start // end // data resolve // reject状态 async function foo() { console.log('start') throw new Error('reject') } async function bar() { try { const data = await foo() console.log('data', data) } catch (err) { console.log('data', err.message) } } bar() console.log('end') // start // end // data reject
await 只能在 async 函数里使用,否则会报错
循环中的 async/await
首先思考下面两个场景:
-
有一个异步请求,需要多次并且按顺序发送
-
有一个异步请求,需要多次发送,但不用按顺序
场景一
同一个请求,多次,按顺序。这就是一个典型的串行处理
function mockServer(i) { return new Promise((reslove, rejecy)=> { setTimeout(() => { reslove('有值了:' + i) }, 1000 * i) }) } async function getData(time) { var data = await mockServer(time) return data } var arr = [1,2,3,4] async function showData() { console.time('showData') for (const item of arr) { const data = await getData(item) console.log(data) } console.timeEnd('showData') } showData() // 有值了: 1 // 有值了: 2 // 有值了: 3 // 有值了: 4 // howData: 13100.510009765625ms
我们通过 for-of 循环调用了 4 次异步函数 getData,由于 getData 前面加了关键字 await,所以会依次排队处理,一共花了13秒多的时间。
场景二
同一个请求,多次,不按顺序。这就是一个典型的并行处理,每个请求同时发送,而不用排队等候,节约时间。
function mockServer(i) { return new Promise((reslove, rejecy)=> { setTimeout(() => { reslove('有值了:', i) }, 1000 * i) }) } async function getData(time) { var data = await mockServer(time) return data } var arr = [1,2,3,4] async function showData() { console.time('showData') var allAsyncRequest = arr.map(item => getData(item)) for await (const asyncRequest of allAsyncRequest) { const data = asyncRequest console.log(data) } console.timeEnd('showData') } showData() // 有值了: 1 // 有值了: 2 // 有值了: 3 // 有值了: 4 // showData: 4131.318115234375ms
我们在 map 的回调里调用了 4 次异步请求函数,将请求事件放到事件队列里面,让 4 个请求可以同时处理,而不影响后续任务的执行。
然后再通过 for await...of 来等待 4 个异步请求都执行完,一共花了 4 秒,大大节约了时间。
这里的 for await...of 还可以换一种写法:
for (const asyncRequest of allAsyncRequest) { const data = await asyncRequest console.log(data) }
也可以使用 Promise.all() :
Promise.all(allAsyncRequest).then((data) => { console.log(data) console.timeEnd('showData') }) // ["有值了:1", "有值了:2", "有值了:3", "有值了:4"] // showData: 4441.679931640625ms
注意:这里不能使用
forEach来进行循环处理,具体原因可以看 当async/await遇上forEach,这篇文章已经写的很清楚了。
最后
学会熟练使用 async/await,可以很好提升代码的可阅读和可维护性,大家如果还有更好的用法和建议,欢迎在评论区补充。
Metadata
Metadata
Assignees
Labels
No labels