Promise ,async/await 基本用法
前言
异步代码的执行在JavaScript中总是以
callback
(回调) 函数的执行来处理
但有多个异步执行等待的程序的时候,常见的结果可能是一个回调地狱
本文参考地址
代码结构看起来是这个样子的:
下图 图片来源:知乎,侵删
Promise 基本结构
Promise
是一个对象
new Promise()
Promise
的构造函数传入参数:一个函数
new Promise(()=>{
})
该函数接收的参数为,两个callback
resolve
, 执行成功的回调
reject
, 执行过程中任何一个失败,就会执行的回调
new Promise((resolve,reject )=>{
})
Promise 发起 ajax
这里不使用
jQuery
的$.ajax
, 因为jQuery
的ajax
,已经被封装了一次,返回了一个Promise
对象使用原生的编程方式发送
ajax
:
let p = new Promise((resolve,reject)=>{
let xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = () => {
console.log(xmlhttp.readyState,xmlhttp.status)
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
console.log("before call resolve")
resolve( xmlhttp.responseText) // 在完成响应后,且状态200 OK时,执行then
}
else if (xmlhttp.readyState==4 && xmlhttp.status!=200)
{
console.log("before call reject")
reject(xmlhttp.responseText) // 在完成响应后,状态异常时,执行catch
}
}
xmlhttp.open("POST","http://192.168.15.16:8080/educloud/getHttpActionList",true);
xmlhttp.send();
}).then((data)=>{
alert("success")
console.log(data)
}).catch((err)=>{
alert("err")
console.log(err)
})
readyState
五个状态代表的意义
- 0:未初始化,但是已经创建了XHR实例
- 1:调用了open()函数
- 2:已经调用了send()函数,但还未收到服务器回应
- 3:正在接受服务器返回的数据
- 4:完成响应
Promise 多个异步的情况下
Promise.all()
如果有两个 promise
难道就这么写?
let p1;
let p2;
p1.then(
function(){
p2.then()
},
function(){
alert('failed')
}
);
// 岂不是看起来更辣鸡吗?
使用 Promise.all()
Promise.all(); // 承诺所有
Promise.all().then() //链式操作 点then()
Promise.all(
[p1,p2] // all方法接收一个 数组作为参数,将你要异步操作的 承诺 p 放入其中
).then(
function(){}, //所有的成功 resolve 才算 成功
function(){} //有一个失败 reject 就算 失败
);
all
是&&
关系 都得成功才成功
Promise.race()
Promise.race() // 竞速 比如同时读五个资源,谁先来了 我用谁,谁先完成 我先运行谁
race
是||
关系 有一个成功就行
async/await 修饰符
参考了大佬的博客
https://www.cnblogs.com/liquanjiang/p/11409792.html
async
async 是一个修饰符,async 定义的函数会默认的返回一个Promise对象resolve的值,因此对async函数可以直接进行then操作
async function fun1() {
console.log(2)
return 1
}
fun1().then( x => { console.log(x) })
// 输出结果 2, 1,
也可返回一个新的Promise
async function fun2() {
console.log('Promise1')
return new Promise(function(resolve, reject){
resolve('Promise2')
})
}
fun2().then( x => { console.log(x) })
// 输出
Promise1
Promise2
Promise {<resolved>: undefined}
await
await
也是一个修饰符,
await
关键字只能放在标识了async
的函数的内部,await
关键字的作用 就是获取Promise
中返回的内容, 获取的是Promise
函数中resolve
或者reject
的值
vuex
中 actions
与后台的交互
async fillModuleConfig({commit}){ //vue store中 actions 提交 mutations
await axios({
method:'post',
url:'http://192.168.15.16:8080/educloud/getHttpModuleList',
}).then(function (response) {
commit('setModuleConfig',response.data.list)
})
}
在组件中调用了fillModuleConfig()
方法
this.fillModuleConfig().then(()=>{ //这里的this 是组件实例本身,无实际意义
// 成功时执行
}).catch(()=>{
// 失败时执行
})
上面这段代码,是定义一个函数
fillModuleConfig
,并且用async
标识该函数是一个异步执行的函数在函数执行体中,使用了
axios
的封装来发送ajax
,axios
已经实现了一套Promise
,所以可以使用.then()
方法
然后使用
await
标识 等待ajax
代码执行完毕
最后在
ajax
代码执行完毕后,再执行一次resolve
或者是reject
的逻辑 (调用函数的地方)
以同步代码的编写方式,写出异步代码的逻辑
const asy = function(x, time) {
return new Promise((resolve, reject) =>{
setTimeout(()=>{
resolve(x)
}, time)
})
}
const add = async function() {
const a = await asy(3, 5000)
console.log(a)
const b = await asy(4, 10000)
console.log(b)
const c = await asy(5, 15000)
console.log(c)
console.log(a,b,c)
const d = a + b +c
console.log(d)
}
add();
5秒后输出 :
3
10秒后输出:
4
15秒后输出:
5
3
,4
,5
12
如果
await
后面并不是一个Promise
的返回值,则会按照同步执行处理
看到这里,代码就演变成了:
.
如果需要在等待执行n个异步操作后,再执行最后一个方法,那么最开始的 Promise
发起 ajax
的方法我们可以改写:
function todoGetData() {
return new Promise((resolve,reject)=>{
let xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = () => {
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
console.log("before call resolve")
console.log(xmlhttp.responseText)
resolve("ok")
}
else if (xmlhttp.readyState==4 && xmlhttp.status!=200)
{
console.log("before call reject")
reject("error")
}
}
xmlhttp.open("POST","http://192.168.15.16:8080/educloud/getHttpActionList",true);
xmlhttp.send();
})
}
async function func() {
await todoGetData().then((data)=>{
console.log(data)
})
//... 还可以写更多的异步代码配合 await使用
console.log("all done")
}
func()
在成功的情况下依次输出:
before call resolve
xmlhttp.responseText中的数据
ok
all done