链式调用
同步代码和异步代码
同步代码:逐行执行,需原地等待结果后,才继续向下执行.
异步代码:调用后耗时,不阻塞代码继续执行(不必原地等待),在将来完成后触发回调函数传递结果
常见异步代码:
- 定时器:setTimeout / setInterval
- 事件(点击事件······)
- AJAX
回调函数地狱
概念:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱
在异步代码中,因为会通过回调函数来传递结果,所有可能会造成回调函数地狱
Promise 链式调用
Promise 对象在进行 .then() 方法后,会返回一个全新的Promise 对象
另外,可以使用return来设置返回的Promise 对象
可以利用这个新Promise 对象,来跳出回调函数地狱
const p = new Promise((resolve, reject) => {
resolve('ok')
})
//调用情况1
p.then(result => {
console.log(result)
return new Promise((resolve, reject) => {
resolve('ok')
})
}).then(result => {
console.log(result)
})
//调用情况2
const p2 = p.then(result => {
console.log(result)
return new Promise((resolve, reject) => {
resolve('ok')
})
})
p2.then(result => {
console.log(result);
})
axios 链式调用
axios本质是permise对象,也可以使用链式调用
// 1. 得到-获取省份Promise对象
let pname = ''
axios({ url: 'http://hmajax.itheima.net/api/province' }).then(result => {
pname = result.data.list[0]
// 2. 得到-获取城市Promise对象
return axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } })
}).then(result => {
const cname = result.data.list[0]
// 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]
console.log(areaName);
})
async 函数和 await关键字
async 函数和 await关键字可以简化通过Promise 对象所写的异步代码
原理:在 async 函数内,使用 await 关键字可以取代 then 函数,等待获取 Promise 对象成功状态的结果值
// 1. 定义async修饰函数
async function getData() {
// 2. await等待Promise对象成功的结果
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 areaName = aObj.data.list[0]
事件循环
概念
事件循环是JS运行代码顺序的机制,是执行代码和收集异步任务的模型
执行机制:
- 首先自上而下在调用栈中执行同步代码
- 遇到异步代码,则将异步代码交给宿主浏览器环境执行
- 异步代码有结果后,回调函数放入任务队列
- 调用栈空闲后(同步代码全部执行完)调用任务队列中的回调函数
例: 以下输出结果为 1 5 3 2 4
/**
* 目标:阅读并回答执行的顺序结果
*/
console.log(1)
setTimeout(() => {
console.log(2)
}, 0)
function myFn() {
console.log(3)
}
function ajaxFn() {
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://hmajax.itheima.net/api/province')
xhr.addEventListener('loadend', () => {
console.log(4)
})
xhr.send()
}
for (let i = 0; i < 1; i++) {
console.log(5)
}
ajaxFn()
document.addEventListener('click', () => {
console.log(6)
})
myFn()
宏任务与微任务
异步任务分为宏任务与微任务
- 宏任务:由浏览器环境执行的异步代码
- 微任务:由 JS 引擎环境执行的异步代码
执行时优先微任务
Promise.all 静态方法
用于合并多个 Promise 对象,等待所有同时成功完成(或某一个失败),做后续逻辑
// 1. 请求城市天气,得到Promise对象
const bjPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '110100' } })
const shPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '310100' } })
const gzPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '440100' } })
const szPromise = axios({ url: 'http://hmajax.itheima.net/api/weather', params: { city: '440300' } })
// 2. 使用Promise.all,合并多个Promise对象
const p = Promise.all([bjPromise, shPromise, gzPromise, szPromise])
p.then(result => {
// 注意:结果数组顺序和合并时顺序是一致
console.log(result)
const htmlStr = result.map(item => {
return `<li>${item.data.data.area} --- ${item.data.data.weather}</li>`
}).join('')
document.querySelector('.my-ul').innerHTML = htmlStr
}).catch(error => {
console.dir(error)
})