一.同步代码和异步代码
1. 同步代码:
逐行执行,需原地等待结果后,才继续向下执行
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)
结果:1, 4, 2
按钮点击一次打印一次 3
二.回调函数地狱
1. 需求:
展示默认第一个省,第一个城市,第一个地区在下拉菜单中
2. 概念:
在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱
3. 缺点:
可读性差,异常无法捕获,耦合性严重,牵一发动全身
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 => {const cname = result.data.list[0]document.querySelector('.city').innerHTML = cname// 获取第一个城市默认下属第一个地区名字axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } }).then(result => {document.querySelector('.area').innerHTML = result.data.list[0]})})
})
三.Promise链式调用
1. 概念:
依靠 then() 方法会返回一个新生成的 Promise 对象特性,继续串联下一环任务,直到结束
2. 细节:
then() 回调函数中的返回值,会影响新生成的 Promise 对象最终状态和结果
3. 好处:
通过链式调用,解决回调函数嵌套问题
4. 按照图解,编写核心代码:
/*** 目标:掌握Promise的链式调用* 需求:把省市的嵌套结构,改成链式调用的线性结构
*/
// 1. 创建Promise对象-模拟请求省份名字
const p = new Promise((resolve, reject) => {setTimeout(() => {resolve('北京市')}, 2000)
})// 2. 获取省份名字
const p2 = p.then(result => {console.log(result)// 3. 创建Promise对象-模拟请求城市名字// return Promise对象最终状态和结果,影响到新的Promise对象return new Promise((resolve, reject) => {setTimeout(() => {resolve(result + '--- 北京')}, 2000)})
})// 4. 获取城市名字
p2.then(result => {console.log(result)
})// then()原地的结果是一个新的Promise对象
console.log(p2 === p)
四.Promise链式调用:解决回调地狱
1. 目标:
使用 Promise 链式调用,解决回调函数地狱问题
2. 做法:
每个 Promise 对象中管理一个异步任务,用 then 返回 Promise 对象,串联起来
3. 按照图解思路,编写核心代码:
/*** 目标:把回调函数嵌套代码,改成Promise链式调用结构* 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中
*/
let pname = ''
// 1. 得到-获取省份Promise对象
axios({url: 'http://hmajax.itheima.net/api/province'}).then(result => {pname = result.data.list[0]document.querySelector('.province').innerHTML = pname// 2. 得到-获取城市Promise对象return axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }})
}).then(result => {const cname = result.data.list[0]document.querySelector('.city').innerHTML = cname// 3. 得到-获取地区Promise对象return axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }})
}).then(result => {console.log(result)const areaName = result.data.list[0]document.querySelector('.area').innerHTML = areaName
})
小结
1. 什么是同步代码?
逐行执行,原地等待结果后,才继续向下执行
2. 什么是异步代码?
调用后耗时,不阻塞代码执行,将来完成后触发回调函数
3. JS 中有哪些异步代码?
setTimeout / setInterval,事件,AJAX
4. 异步代码如何接收结果?
依靠回调函数来接收
5. 什么是回调函数地狱?
在回调函数一直向下嵌套回调函数,形成回调函数地狱
6. 回调函数地狱问题?
可读性差,异常捕获困难,耦合性严重
7. 什么是 Promise 的链式调用?
使用 then 方法返回新 Promise 对象特性,一直串联下去
8. then 回调函数中,return 的值会传给哪里?
传给 then 方法生成的新 Promise 对象
9. Promise 链式调用有什么用?
解决回调函数嵌套问题
10. Promise 链式调用如何解决回调函数地狱?
then 的回调函数中 return Promise对象,影响当前新 Promise 对象的值