Async/Await
一、Async/Await 是什么
(一)Async 函数
async
是一个关键字,用于声明一个异步函数。
async function 声明创建一个绑定到给定名称的新异步函数。函数体内允许使用 await 关键字,这使得我们可以更简洁地编写基于 promise 的异步代码,并且避免了显式地配置 promise 链的需要。
(二)Await 关键字
await 表达式通过暂停执行使返回 promise 的函数表现得像同步函数一样,直到返回的 promise 被兑现或拒绝。返回的 promise 的解决值会被当作该 await 表达式的返回值,它的作用是暂停异步函数的执行,等待右侧的 Promise 完成后,再恢复执行并返回 Promise 的结果。
简单说,await
让异步代码看起来像同步代码,但不会阻塞整个线程。
async function fetchData() {// 等待 Promise 完成,拿到结果后继续执行const response = await fetch("https://api.example.com/data"); const data = await response.json();return data;
}
每个 await 表达式之后的代码可以被认为存在于 .then 回调中。通过这种方式,可以通过函数的每个步骤来逐步构建 promise 链。
二、为什么需要 Async/Await
回调地狱问题
这是一个要实现省市县下拉框的案例,我们先默认选取第一个值作为渲染,这样写出来就构成了下方的在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱,造成异常无法获取,耦合性严重,牵一发动全身的问题。
axios({ url: 'http://hmajax.itheima.net/api/province', }).then(result => {const pname = result.data.list[0];document.querySelector('.province').innerHTML = pname;axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname, } }).then((result) => {console.log(result);const cname = result.data.list[0];document.querySelector('.city').innerHTML = cname;axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname, } }).then((result) => {console.log(result);const areaObj = result.data.list;const areas = areaObj.map(item => {return `<option class="area">${item}</option>`;}).join('');document.querySelector('#area').innerHTML = areas;})})})
使用Promise 解决了回调地狱的问题
Promise 链式调用
axios({ url: 'http://hmajax.itheima.net/api/province' }).then(result => {console.log(result);pname = result.data.list[0];document.querySelector('.province').innerHTML = pname;return axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } });}).then((result) => {console.log(result);cname = result.data.list[0];document.querySelector('.city').innerHTML = cname;return axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname: pname, cname: cname } });}).then(result => {console.log(result);const areaname = result.data.list[0];document.querySelector('.area').innerHTML = areaname;})
Async/Await 则让异步代码更接近同步代码的线性逻辑:
async function getData() {const pObj = await axios({url: 'http://hmajax.itheima.net/api/province',});const pname = pObj.data.list[0];console.log(pObj);const cObj = await axios({url: 'http://hmajax.itheima.net/api/city',params: {pname: pname,}});const cname = cObj.data.list[0];const aObj = await axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } });const aname = aObj.data.list[0];document.querySelector('.province').innerHTML = pname;document.querySelector('.city').innerHTML = cname;document.querySelector('.area').innerHTML = aname;}getData();
Async/Await 用线性的写法替代了链式调用,逻辑更直观
三、Async/Await 的使用
(一)处理多个异步操作
比如“先请求用户信息,再根据用户 ID 请求订单列表”
async function getUserOrders() {const user = await fetchUser(); // 第一步异步const orders = await fetchOrders(user.id); // 依赖第一步的结果return { user, orders };
}
(二)并行与串行结合
如果多个异步操作互不依赖,可以用 Promise.all
并行执行以提升效率,再用 await
等待全部完成:
async function fetchAll() {// 并行执行,缩短总耗时const p = await Promise.all([fetchUser(),fetchProducts(),fetchPosts()]);return p;
}