本节目标
- 导学
- 同步代码
- 异步代码
- 回调地狱
导学
以下代码的执行结果是什么?
<body>
<button class="btn">点我</button>
<script>
// 目标:阅读并回答代码执行和打印的顺序
// 结果: 1, 4, 2, 点击按钮打印3
const result = 0 + 1
console.log(result)
setTimeout(() => {
console.log(2)
}, 2000)
document.querySelector('.btn').addEventListener('click', () => {
console.log(3)
})
document.body.style.backgroundColor = 'pink'
console.log(4)
</script>
</body>
同步代码
正常情况下, 浏览器按照顺序执行代码, 上一行代码执行完毕再执行下一行代码 , 这就是同步代码
异步代码
异步代码提高了程序的执行效率, 调用后耗时, 但不阻塞代码继续执行, 异步任务完成后, 通过触发回调函数, 得到执行结果
举例
- 定时器(setTimeout)/延时器(setInterval)
- 事件函数
- AJAX
回调地狱
多个回调函数嵌套, 就形成了回调地狱
缺点
- 可读性差
- 代码耦合严重
- 捕获内部的异常困难
回调地狱
<body>
<form>
<span>省份:</span>
<select>
<option class="province"></option>
</select>
<span>城市:</span>
<select>
<option class="city"></option>
</select>
<span>地区:</span>
<select>
<option class="area"></option>
</select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
/**
* 目标:演示回调函数地狱
* 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中
* 概念:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱
* 缺点:可读性差,异常无法获取,耦合性严重,牵一发动全身
*/
axios({ url: 'http://hmajax.itheima.net/api/province' }).then(({ data }) => {
const pname = data.list[2]
document.querySelector('.province').innerHTML = pname
axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } }).then(({ data }) => {
const cname = data.list[0]
console.log(cname);
document.querySelector('.city').innerHTML = cname
axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } }).then(({ data }) => {
const aname = data.list[0]
console.log(aname);
document.querySelector('.area').innerHTML = aname
})
})
})
</script>
</body>
链式调用
then()方法会返回一个新的Promise对象,可以继续串联下一环任务, 直到任务结束
then()方法中回调函数的返回值, 会传递给新生成的Promise对象
<body>
<form>
<span>省份:</span>
<select>
<option class="province"></option>
</select>
<span>城市:</span>
<select>
<option class="city"></option>
</select>
<span>地区:</span>
<select>
<option class="area"></option>
</select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
/**
* 目标:把回调函数嵌套代码,改成Promise链式调用结构
* 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中
*/
let pname = ''
axios({ url: 'http://hmajax.itheima.net/api/province' }).then(({ data }) => {
pname = data.list[3]
document.querySelector('.province').innerHTML = pname
return axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } })
}).then(({ data }) => {
const cname = data.list[0]
document.querySelector('.city').innerHTML = cname
return axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } })
}).then(({ data }) => {
document.querySelector('.area').innerHTML = data.list[0]
})
</script>
</body>
async/await
在async函数中允许使用await关键字, 取代then函数, 等待获取Promise对象的结果, 更方便的实现链式调用
async和await是ES8引入的新语法,用来简化Promise异步操作
<body>
<form>
<span>省份:</span>
<select>
<option class="province"></option>
</select>
<span>城市:</span>
<select>
<option class="city"></option>
</select>
<span>地区:</span>
<select>
<option class="area"></option>
</select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
/**
* 目标:掌握async和await语法,解决回调函数地狱
* 概念:在async函数内,使用await关键字,获取Promise对象"成功状态"结果值
* 注意:await必须用在async修饰的函数内(await会阻止"异步函数内"代码继续执行,原地等待结果)
*/
async function getData() {
const pObj = await axios({ url: 'http://hmajax.itheima.net/api/province' })
const pname = pObj.data.list[0]
const cObj = await axios({ url: 'http://hmajax.itheima.net/api/city', params: { 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()
</script>
</body>
try/catch
try/catch语句标记可能出错的语句,出错后捕获错误信息, 并执行catch中的代码
<script>
/**
* 目标:async和await_错误捕获
*/
async function getData() {
try {
const pObj = await axios({ url: 'http://hmajax.itheima.net/api/province' })
const pname = pObj.data.list[0]
const cObj = await axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } })
const cname = cObj.data.list[0]
const aObj = await axios({ url: 'http://hmajax.itheima.net/api/area1', params: { pname, cname } })
const areaName = aObj.data.list[0]
document.querySelector('.province').innerHTML = pname
document.querySelector('.city').innerHTML = cname
document.querySelector('.area').innerHTML = areaName
} catch (error) {
console.dir(error)
}
}
getData()
</script>
错误信息
- message信息是axios返回的错误信息
- responses信息是服务器返回的错误信息