Vue 03
异步的结果是否可以使用返回值获取?不可以(返回结果的时机不确定)
那么必须使用回调函数的方式获取异步的结果
如果要保证异步任务的顺序,需要进行回调函数的嵌套
但是嵌套过多会出现地狱回调问题(代码可读性差)
所以诞生了新的技术解决上述问题:Promise
但是Promise也不是最好的方案,所以诞生了Async函数(最终解决方案)
异步编程-promise
promise是一种技术,用于解决回调地狱问题
promise基本用法
// 基于Promise发送请求
const p = new Promise(function (resolve, reject) {
// 这里用于处理异步的任务
const xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:3000/data')
xhr.send(null)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 获取正常的数据
let ret = xhr.responseText
let obj = JSON.parse(ret)
// 正常的结果传递给resolve即可
resolve(obj)
} else {
// 返回的数据是异常的
// 异常的结果需要传递给reject
reject('服务器返回的数据错误')
}
}
}
})
// 通过p.then方法获取异步的结果
p.then(function (ret) {
// 这里可以得到正常的结果
console.log(ret)
}).catch(function (err) {
// 这里可以得到异常的结果
console.log(err)
})
总结:
1.熟悉基于Promise处理异步任务的基本流程
2.正常的结果传递给resolve;异常的结果传递给reject
3.通过p.then获取正常的结果,p.catch获取异常的结果
解决回调地狱的问题
function queryData1() {
// 基于Promise发送请求
return new Promise(function (resolve, reject) {
// 这里用于处理异步的任务
const xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:3000/data1')
xhr.send(null)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 获取正常的数据
let ret = xhr.responseText
let obj = JSON.parse(ret)
// 正常的结果传递给resolve即可
resolve(obj)
} else {
// 返回的数据是异常的
// 异常的结果需要传递给reject
reject('服务器返回的数据错误')
}
}
}
})
}
function queryData2() {
// 基于Promise发送请求
return new Promise(function (resolve, reject) {
// 这里用于处理异步的任务
const xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:3000/data2')
xhr.send(null)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 获取正常的数据
let ret = xhr.responseText
let obj = JSON.parse(ret)
// 正常的结果传递给resolve即可
resolve(obj)
} else {
// 返回的数据是异常的
// 异常的结果需要传递给reject
reject('服务器返回的数据错误')
}
}
}
})
}
function queryData3() {
// 基于Promise发送请求
return new Promise(function (resolve, reject) {
// 这里用于处理异步的任务
const xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:3000/data3')
xhr.send(null)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 获取正常的数据
let ret = xhr.responseText
let obj = JSON.parse(ret)
// 正常的结果传递给resolve即可
resolve(obj)
} else {
// 返回的数据是异常的
// 异常的结果需要传递给reject
reject('服务器返回的数据错误')
}
}
}
})
}
// 如下代码执行的流程是串行的
queryData1()
.then(function (ret) {
console.log(ret)
return queryData2()
})
.then(function (ret) {
console.log(ret)
return queryData3()
})
.then(function (ret) {
console.log(ret)
})
关于promise的异常处理
// 如下代码执行的流程是串行的
queryData1()
.then(function (ret) {
console.log(ret)
// 如果then中出现了异常情况,那么后续的then就不再执行了
const arr = null
arr.push(123)
return queryData2()
})
.then(function (ret) {
console.log(ret)
return queryData3()
})
.then(function (ret) {
console.log(ret)
})
.catch(function (err) {
// 这里用于处理异常信息
console.log(err)
})
总结:
1.如果then中出现了异常情况,那么后续的then就不在执行了
2.一般会在then的最后添加一个catch,统一异常处理
then的回调返回值问题
// 如下代码执行的流程是串行的
queryData1()
.then(function (ret) {
console.log(ret)
// 如果then中出现了异常情况,那么后续的then就不再执行了
// const arr = null
// arr.push(123)
return queryData2()
})
.then(function (ret) {
console.log(ret)
// 1、这里return的值是谁?Promise的实例对象
// 如果这里return的是Promise的实例对象,那么
// 下一个then会得到这个Promise的异步结果
// 其实就是这个Promise对象调用了下一个then
return queryData3()
})
.then(function (ret) {
console.log(ret)
// 2、如果这里没有返回值,那么会默认生成一个Promise对象并返回
// return new Promise(function (resolve) {
// resolve()
// })
})
.then(function (ret) {
console.log(ret)
console.log('---------------------')
// 3、如果这里返回的是普通数据,那么下一个then可以直接得到该数据
// 如果返回的是普通数据,会自动包装为Promise实例对象
return 'hello'
// return new Promise(function (resolve) {
// resolve('hello')
// })
})
.then(function (ret) {
console.log(ret)
})
.catch(function (err) {
// 这里用于处理异常信息
console.log(err)
})
总结:
1.then回调函数返回promise对象,下一个then得到这个promise任务的结果
2.then回调函数返回普通数据,下一个then可以直接得到这个数据(数据被默认包装成了promise对象)
3.then回调函数没有返回,但是可以继续then链式操作(默认返回了一个promise实例对象,但是没有值)
异步编程-Async函数
Async函数基本用法
// Asyn函数基本使用
function queryData() {
// 基于Promise发送请求
return new Promise(function (resolve, reject) {
// 这里用于处理异步的任务
const xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:3000/data')
xhr.send(null)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 获取正常的数据
let ret = xhr.responseText
let obj = JSON.parse(ret)
// 正常的结果传递给resolve即可
resolve(obj)
} else {
// 返回的数据是异常的
// 异常的结果需要传递给reject
reject('服务器返回的数据错误')
}
}
}
})
}
// queryData().then(function (ret) {
// console.log(ret)
// })
// 如下就是定义了一个async函数,可以处理异步任务
async function getInfo() {
// await关键自必须在async函数中使用
// await之后一般跟Promise实例对象
// const ret = await queryData()
// console.log(ret)
// 通过Promise的then方式获取结果和await获取结果等效
queryData().then(function (ret) {
console.log(ret)
})
}
getInfo()
总结:
- 定义async函数仅仅需要在函数声明的左侧添加async关键字
- await关键字必须出现在async函数内部
- await关键字之后一般会跟Promise实例对象
- await代码行之后的代码是阻塞的
Async处理多个异步任务
// 要求:获取的顺序 jerry -> spike -> tom
async function getResult() {
const ret2 = await queryData2()
const ret3 = await queryData3()
const ret1 = await queryData1()
console.log(ret2)
console.log(ret3)
console.log(ret1)
}
getResult()
总结:
- 基于Async函数处理回调地狱可以按照同步的风格写代码,体验很好
- 多个await运行模式是串行的
Async函数和promise的关系
// Promise和Async函数的关系
// 1、await之后一把跟Promise实例对象,await左侧接收的值就是Promise异步任务的结果
// 2、async函数的返回值是Promise对象,而不是具体数据
function queryData() {
// 基于Promise发送请求
return new Promise(function (resolve, reject) {
// 这里用于处理异步的任务
const xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:3000/data')
xhr.send(null)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 获取正常的数据
let ret = xhr.responseText
let obj = JSON.parse(ret)
// 正常的结果传递给resolve即可
resolve(obj)
} else {
// 返回的数据是异常的
// 异常的结果需要传递给reject
reject('服务器返回的数据错误')
}
}
}
})
}
async function getInfo() {
const ret = await queryData()
// console.log(ret)
return ret
// 这里返回的数据实际上会默认包装为Promise实例对象
// return new Promise(function (resolve) {
// resolve(ret)
// })
}
// async函数的返回值是Promise对象,而不是具体数据
const t = getInfo()
// console.log(t)
t.then(function (ret) {
console.log(ret)
})
总结:
- await之后一把跟Promise实例对象,await左侧接收的值就是Promise异步任务的结果
- async函数的返回值是Promise对象,而不是具体数据
axios调用接口
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
// axios调用接口
// axios.get('http://localhost:3000/data').then(function (ret) {
// console.log(ret.data)
// })
axios.defaults.baseURL = 'http://localhost:3000/'
async function getResult() {
const ret = await axios.get('data')
console.log(ret.data)
}
getResult()
// 如下的伪代码
new Vue({
el: '#app',
data: {
list: []
},
methods: {
// loadBookList: async function () {
// const ret = await axios.get('data')
// this.list = ret.data
// },
async loadBookList() {
const ret = await axios.get('data')
this.list = ret.data
}
}
})
</script>
</body>
总结:
- axios库底层封装了Promise,所有他的API一般都支持Promise方式
- 基于async函数处理axios的接口调用会变得异常简单