一.Promise是啥
1.阮大佬的解释
2.看不懂,直接打印
可以看到,这是个构造函数,自己有all,race,reject,resolve方法,原型上有 then,catch方法
3.特点
- 只有三种状态pending(正在进行),fulfilled(已成功),rejected(已失败)
- 只有两种状态转换
- pending===>fulfilled
- pending===>rejected
- 状态一旦转换,不会再改变,且promise对象无法自动销毁,任何时候都可以获取执行结果
二.啥也不管,用了再说
1.new一个先
let p = new Promise((resolve,reject)=>{
console.log('123')
setTimeout(()=>{
console.log('执行结束')
resolve(321)
},2000)
})
结果:
上面先执行了随便什么操作,两秒后执行了resolve,打印了执行结束
啥是resolve和reject?
已经知道这是在构造函数Promise上的方法,es6标准上讲resolve是将异步操作状态从pending转为fulfilled,而reject是将状态从pending转为rejected
看不懂?那继续show you the code
2.then方法,以及为什么promise支持链式操作?
<strong><span style="color:hotpink">show you the code</span></strong>
p.then((data)=>{
console.log(data)
})
看结果返回了一个promise对象,我们知道promise原型上有then方法,因此可以链式操作,很爽!!!
打印了321,说明resolve传出的数据我们可以在then中操作,因此便可以在then中为异步操作的成功或失败状态后设置回调函数,让代码看起来更像同步操作.(解决了回调地狱这个事儿)
关于什么是回调地狱,参考:
[https://juejin.im/post/5ae7aa796fb9a07ab83dcfa6]:
简单理解就是函数作为参数层层被调用,会是代码耦合度极高,不利于维护
提问:还有什么别的方法可以解决嘛?
tip:es7中的async/await =====>这被称为解决异步问题的终极方法
悄咪咪的说,也不过是语法糖罢了,不过,架不住它好吃啊
3.造一个函数作为参数层层调用的例子
小明跟爸爸说小明要吃烤肉,爸爸说让小明去买材料,买完材料回来爸爸制作,制作完小明就赶紧吃了溜(就不刷碗!!!!)
先定义几个方法
let async1 = () => {
let p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('买材料')
resolve('买完材料了')
}, 2000)
})
return p
}
let async2 = () => {
let p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('制作')
resolve('制作完成,赶紧吃')
}, 2000)
})
return p
}
let async3 = () => {
let p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('吃完赶紧溜')
resolve('就不刷碗')
}, 2000)
})
return p
}
如何描述上面的例子?
<span style="color:hotpink">show you the code</span>
async1().then((data) => {
console.log(data)
return async2()
}).then((data) => {
console.log(data)
return async3()
}).then((data) => {
console.log(data)
})
运行结果
一步一步,上一步函数的调用结果作为下一步的参数,将异步操作以同步操作的流程表达出来,避免层层嵌套,完美.
4.reject是啥?
经过上面的例子,应该大概了解了promise是啥,但是里面好像还有个reject我们还没看,来,继续上面的例子
众所周知,小明是一个调皮的但是注意力不集中的好孩子,在路上,他发现了好甜的水果糖,于是买了水果糖,结果回到家到了第二调用,便带了个error
<span style="color:hotpink">show you the code</span>
// 改一下async1()
let async1 = () => {
let p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('买材料')
console.log('看到糖果')
console.log('买了糖果')
if(/*买对了*/ 0){
resolve('买了材料')
}else{
reject('买了糖果')
}
}, 2000)
})
return p
}
// 描述故事
async1().then((data) => {
console.log(data)
return async2()
},(err)=>{
console.log('买错了,快滚')
return
})
//为了描述上面的例子,这里只做了第一步调用
结果:
由结果看,then(parm1,parm2)的两个参数,第一个为处理resolve的状况,给resolve添加函数处理,而第二个参数为处理reject的状况,两个参数都为处理函数.
第一个处理函数的参数为resolve传过来的数据,第二个的参数为reject传过来的数据.
5.catch?
单词的一次就是捕获,所以作用是捕获异常,参数为异常处理函数,也就是跟then的第二个参数一样,因此不再赘述,但是catch有自己的独特的作用(不然凭啥存在)
话不多说,<span style="color:hotpink">show you the code</span>
const fun = () => {
let p = new Promise((resolve, reject) => {
resolve(123)
})
return p
}
fun().then((data)=>{
console.log(data)
console.log(names)
})
上面的例子运行会报names is not defined 的错误,而且不会继续运行了,如果后面有代码会直接中断,而如果加了catch
fun().then((data)=>{
console.log(data)
console.log(names)
}).catch((res)=>{
console.log('出错咯')
}).then((data)=>{
console.log('123')
})
看结果
由此,代码出错,会被catch捕获,并做处理,然后可以继续运行代码.
6.race和all方法
all方法
还是用小明的例子
我们先把延时时间改一下,比如async1改为4s,async2改为3s,async3改为2s
Promise.all([async1(),async2(),async3()])
// all里传的参数为promise实例的数组
看结果
all方法提供的是并行执行异步操作的能力
Promise.all()方法的参数为一个数组,数组里各元素均为promise实例,如果不是,会先转换为promise实例.
注意
- 全部执行完异步操作才会进入then处理每个异步操作的返回数据.
简单理解就是以跑的慢的为准,跑的慢的跑完了才一起处理返回结果.
使用场景
- 加载静态资源全部完成后才需要渲染处理的时候
race方法
相对all方法,这个就是跑的快的为准,有跑完了的就直接执行then里处理函数
于是上面的代码改用race方法后
Promise.race([async1(),async2(),async3()]).then((datas)=>console.log(datas))
结果
async3执行的最快,跑完后便直接处理打印了resolve返回的数据==>'就不刷碗'
使用场景
- 给ajax等异步操作请求设置超时时间
至此,最常用的promise的方法都已经介绍完毕.
注:文章首发于掘金社区本人账号 努力学习的小咸菜