这篇来说说请求的一些小细节、小知识点
现在的请求处理总是离不开Promise和async/await
串行和并行也就是围绕着这两个玩意去写的
一、先说说并行请求
什么并行请求?
简单来说就是:请求1和请求2同时进行请求
如下图,在控制台中mock1和mock2的请求就是同时进行
提示:看waterfall更佳直观
那如何实现并行请求?
当然需要分情况
对于调用多个后台接口,且都没有直接相关的
只需要用两个函数进行封装,依次调用
例如使用Promise
// 请求1
function requestOne() {
axios.get('http://localhost:5000/mock1')
.then((res) => {
console.log(res.data)
// 请求后做些什么...
})
}
// 请求2
function requestTwo() {
axios.get('http://localhost:5000/mock2')
.then((res) => {
console.log(res.data)
// 请求后做些什么...
})
}
function requestTotal() {
// 依次调用
requestOne()
requestTwo()
}
requestTotal()
async/await也一样,分别用两个函数进行分装
// 请求1
async function requestOne () {
const res = await axios.get('http://localhost:5000/mock1')
console.log(res.data)
// 请求后做些什么...
}
// 请求2
async function requestTwo () {
const res = await axios.get('http://localhost:5000/mock2')
console.log(res.data)
// 请求后做些什么...
}
function requestTotal() {
// 依次调用
requestOne()
requestTwo()
}
requestTotal()
对于调用多个后台接口,且都有直接相关的
例如,我需要对所有的请求结果进行处理
那就是使用Promise.all
对于使用 promise ,那我们代码可以写成这样
// 请求1
function requestOne() {
// 请求成功后返回 Promise 对象
return new Promise((resolve) => {
axios.get('http://localhost:5000/mock1')
.then((res) => {
resolve(res.data)
})
})
}
// 请求2
function requestTwo() {
// 请求成功后返回 Promise 对象
return new Promise((resolve) => {
axios.get('http://localhost:5000/mock2')
.then((res) => {
resolve(res.data)
})
})
}
// 处理所有请求
function requestTotal() {
console.log('requestOne()', requestOne())
console.log('requestTwo()', requestTwo())
// 处理请求1和请求2返回的 Promise 对象
Promise.all([requestOne(), requestTwo()])
.then((res) => {
console.log(res)
// 请求所有后做些什么...
})
}
// 调用
requestTotal()
输出如下
async/await可以改成这样
// 请求1
async function requestOne () {
const res = await axios.get('http://localhost:5000/mock1')
return res.data
}
// 请求2
async function requestTwo () {
const res = await axios.get('http://localhost:5000/mock2')
return res.data
}
// 处理所有请求
function requestTotal() {
// 处理请求1和请求2返回的 Promise 对象
Promise.all([requestOne(), requestTwo()])
.then((res) => {
console.log(res)
// 请求所有后做些什么...
})
}
// 调用
requestTotal()
由于async函数会自动将结果用Promise.resolve包裹,直接返回即可
二、再说说串行请求
什么串行请求?
简单来说就是:请求1 -> 请求2 -> 请求3,这样依次执行
一个简单的场景需求就是:你必须拿请求1返回的数据后,作为请求2参数再去请求
例如:
// 请求1
function requestOne() {
return new Promise((resolve) => {
axios.get('http://localhost:5000/mock1')
.then((res) => {
resolve(res.data)
})
})
}
// 请求2
function requestTwo() {
return new Promise((resolve) => {
axios.get('http://localhost:5000/mock2')
.then((res) => {
resolve(res.data)
})
})
}
// 使用 promise 依次调用
function requestTotal() {
requestOne().then(() => {
requestTwo().then(() => {
})
})
}
// 调用
requestTotal()
如果你觉得requestTotal这个函数写法不优雅,完全可以这样写
// 使用 promise 依次调用
function requestTotal() {
let chain = Promise.resolve()
chain = chain.then(() => requestOne())
chain = chain.then(() => requestTwo())
}
或者这样
function requestTotal() {
Promise.resolve()
.then(() => {
return requestOne()
})
.then(() => {
return requestTwo()
})
}
如果觉得上面也太麻烦了,那就直接上async/await
// 使用 promise 依次调用
async function requestTotal() {
await requestOne()
await requestTwo()
}
👇全部简化代码:
// 请求1
async function requestOne() {
const res = await axios.get('http://localhost:5000/mock1')
return res.data
}
// 请求2
async function requestTwo() {
const res = await axios.get('http://localhost:5000/mock2')
return res.data
}
// 使用 promise 依次调用
async function requestTotal() {
await requestOne()
await requestTwo()
}
// 调用
requestTotal()
这里需要特别提醒小伙伴们使用async/await
有时不要觉得使用async/await就是串行了
例如
// 请求1
function requestOne() {
axios.get('http://localhost:5000/mock1')
.then((res) => {
resolve(res.data)
})
}
// 请求2
function requestTwo() {
axios.get('http://localhost:5000/mock2')
.then((res) => {
// console.log(res.data)
resolve(res.data)
})
}
async function requestTotal() {
await requestOne()
await requestTwo()
}
requestTotal()
这其实个是并行请求!
你需要在调用函数中返回(return)出 Promise 对象
三、不要忽略异常处理
上面的所有代码都没有加入异常捕获,这显然是不好的
异常处理是可以说是项目健壮性的保障,所有请小伙伴们一定要重视
说到异常,很多小伙伴肯定会想到try/catch 和 window.onerror
但,对于 Promise对象来说,他们并不能捕获其中的异常
你应该使用.catch 和 window.onunhandledrejection
但,我不推荐window.onunhandledrejection这种全局异常
而更推荐.catch
例如
function requestTotal() {
Promise.resolve()
.then(() => {
return requestOne()
})
.catch(e => {
// 捕获异常
console.log(e)
})
.then(() => {
return requestTwo()
})
.catch(e => {
// 捕获异常
console.log(e)
})
}
这里有个细节,为什么需要两个 .catch?
如你没有对 requestOne 进行捕获,那么会阻塞requestTwo 运行
例如
function requestTotal() {
Promise.resolve()
.then(() => {
return requestOne()
})
.then(() => {
// requestOne 发生异常,requestTwo 无法执行
return requestTwo()
})
.catch(e => {
// 捕获异常
console.log(e)
})
}
如果小伙伴们决定麻烦,可以使用async/await
async function requestTotal() {
try {
await requestOne()
await requestTwo()
} catch (e) {
console.log(e)
}
}
因为async/await可以被try/catch捕获到
但这样 requestTwo 就无法继续执行
当然具体实现情况应该根据需求进行调整,这里只是强调细节
感谢阅读