小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
1. Async Await
1.1 简介
ES2015
引入了 Promise
来解决“回调地狱”问题,时隔两年,ES2017的 Async-Await
证明Promise
不是最终的解决方案
ES2017
标准引入了 Async Function
的概念,使得异步操作变得更加方便。Async Function
是 Generator
函数的语法糖,从直观上讲就是将Generator
函数的星号(*)替换成async
,将 yield
替换成 await
。
Async Await
比起星号和 yield
,语义更加清晰符合定义,并且 Async Function
函数自带执行器,不需要像 Generator
函数一样调用 next
方法, 或使用co 模块。Async Function
的返回值是Promise
对象,await
命令则是内部then
的语法糖。
1.2 使用
-
Async
函数中,如果返回一个非Promsie
对象,Javascript
会自动将其包装成Promise.resolve()
的值。async function fn() { return 'hello _Battle' // 等同于 return Promise.resolve('hello _Battle') } fn().then((v) => console.log(v)) // 'hello _Battle'
-
若在
Async
函数中抛出错误,会导致返回的Promise
对象的状态变为reject
, 从而可以被catch
捕获。async function fn() { throw new Error('error') } fn().then((v) => console.log(v), (err) => console.log(err)) // Error: error
-
await
命令,只能在async
函数内部使用。 一般情况下,await
命令后接一个Promise
对象,返回该对象Fulfilled
后的结果,如果不是,则直接返回对应的值。async function test() { return await 'hello _Battle' // 等同于 return 'hello _Battle' } test().then((v) => console.log(v)) // "hello _Battle" // 另一种情况,await 接收一个 thenable 对象(具有可调用 then 方法的对象) // 这时await会将其等同于Promise对象。 class Thenable { constructor(num) { this.num = num } then(resolve, reject) { setTimeout(() => resolve(this.num * 2), 1000) } } (async () => { const res = await new Thenable(5) console.log('result:', res) })() // result:10
-
在
async-await
错误处理时,任何一个await
命令后的Promise
变为reject
状态,则会终止async
函数的执行。async function test() { await Promise.reject(new Error('error')) return await Promise.resolve('hello') } await test() // Error: error, 后续不会执行
若我们希望即使一个异步操作失败,也不会终止后续执行, 可以用
try-catch
块单独捕获async function test() { try { await Promise.reject(new Error('error')) } catch (err) { console.log(err) } return await Promise.resolve('hello') } await test() //1、Error: error; 2、‘hello’
-
按顺序完成异步操作
在开发中,常常遇到一组异步操作,需要按顺序输出异步回调的结果。
用
Promise
来实现如下:将fetch返回的
Promise
对 对象放入数组,使用reduce
方法依次处理每个Promise
对象,然后使用then
连接所有Promise
对象实现顺序输出。const logInOrder = (urls) => { // 拉取url数组 const promises = urls.map((item) => { return fetch(item).then((res) => res.text()) } promises().reduce((chain, currentPromise) => { return chain.then(() => currentPromise).then((text) => console.log('text',text)) }, Promise.resolve()) }
用
async
函数改造const logInOrder = async (urls) => { for (const url of urls) { const res = await fetch(url) console.log(await res.text()) } }
上述代码虽然简洁许多, 但是所有 fetch 异步操作都是继发的,原因是async 函数内部的await命令会继发执行, 我们可以对此改造,将外部 urls 的遍历操作提到 async 函数外部,让其并发执行。
并发改造如下:
const logInOrder = async (urls) => { // 并发远程拉取接口 const promises = urls.map(async (url) => { const res = await fetch(url) return res.text() }) } // 按顺序输出 for (const promise of promises) { console.log(await promise) }
-
休眠效果
Javascript 借助 async - await 函数可以让程序停顿指定的时间。
function sleep (delay) { return new Promise((resolve) => { setTimeout(resolve, delay) }) } (async function test() { for (let i = 1; i <= 5; i++) { console.log(i) await sleep(1000) } })() // 1, 2, 3, 4, 5
-
使用
try - catch
, 实现多次重复尝试在开发中,可能因为网络原因导致请求失败, 我们可能需要请求能够重试指定的次数。
const NUMS = 3 async function test() { let i for (i = 0; i < NUMS; ++i) { try { await fetch('http://google.com/this-throws-an-error') break // 若执行成功,终止尝试 } catch (err) {} } console.log(i) // 3 }
点赞支持、手留余香、与有荣焉,动动你发财的小手哟,感谢各位大佬能留下您的足迹。
往期精彩推荐
Vue 虚拟 DOM 搞不懂?这篇文章帮你彻底搞定虚拟 DOM
Git 相关推荐
面试相关推荐
更多精彩详见:个人主页