前言:这是来掘金写的第一篇文章,回首之前用过的CSDN,博客园这些博客网站,觉得掘金的技术氛围更适合我这个标准的95后哈哈。沸点里的人还是蛮有趣的,希望这个圈子可以越来越好。今天我们就来研究一下Promise对象这个小东西,哈哈哈哈,希望能帮到需要帮助的各位小伙伴。
Promise是什么?
英文释义
promise英文释义为"许诺,允诺,(有)可能"
文档解释
1. Promise对象用作异步计算
2. 一个Promise实例表示一个现在,将来或永不会用到的值。
按用途解释一下:
- 首先Promise是用于异步计算的
- 其次可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果。
- 可以在对象之间传递和操作Promise,帮助我们处理队列。 写到这是不是明白了点什么了?没错,这个小东西就是将异步函数改造成了同步方法的执行顺序,就是在我Promise的领域里,各位都是乐色,我把你放在第几个出场,你就得按顺序来。
为什么会有Promise?
大家都知道JS最初是为处理表单而产生的,以操作DOM为主。所以JS里面的很多操作都是异步的,异步操作的主要目的就是为了避免界面冻结,这里就要引入一个概念,同步任务和异步任务的执行顺序了,这个相信大家都不会陌生,因为JS是有一个事件的轮询机制,英文名Event Loop。
事件轮询
详细说一下这个事件轮询吧,JS是单线程的语言,也就是一次只能执行一个任务,现在有一个文件,代码自上而下执行的时候,会遇到同步的任务,也有异步任务。我们引入几个概念哈,当前执行同步任务的线程我们叫做主线程,而异步任务也有他待的地方,叫做任务队列。同步任务的执行顺序就好像你排队去打疫苗,但是只有一个医生,那是不是按排队顺序在不插队的情况下是从第一个执行到最后一个的。异步任务的执行顺序呢,就相当于现在一堆人去打疫苗,还是只有一个医生,但是有几个人呢没带手机,无法出示健康码,这群人排队排到他的时候,医生问他要身份证,但是他没带需要回家里去拿,拿到之后再回来继续排队打疫苗。这里没有带手机的人我们比做异步任务的话,家就是任务队列,所有的异步在开始执行的时候都会先按顺序挂载到任务队列中,任务队列遵循先进先出的原则,等到同步任务执行完毕之后,主线程便会询问任务队列有没有要执行的异步任务,根据先进先出的原则执行异步任务,当然异步任务也有微任务和宏任务之分,这个我们后面在说。
Node.js出现
- Node.js无阻塞高并发是其竞争力所在
- 想要支持无阻塞高并发必须依靠异步事件
- 大量的操作都依赖于回调函数
回调函数的缺陷"回调地狱"
let resA = []
let resB = []
function a(){
axios.get('urla').then(res =>{
resA = res
})
}
function b(resA){
axios.get('urlb',{
params: resA
}).then(res =>{
resB = res
})
function c(resB){
axios.get('urlc',{
params: resB
}).then(res =>{
return res
})
}
现在我要输出吃c(),那就必须保证a,b,c三个函数的按顺序执行,那么函数就会这样写:
function a(){
axios.get('urla').then(res =>{
resA = res
if(resA){
axios.get('urlb',{
params: resA
}).then(res =>{
resB = res
if(resB){
axios.get('urlc',{
params: resB
}).then(res =>{
return res
})
}
})
}
})
}
想像一下如果有100个接口需要嵌套调用的话,代码的可读性和可维护性讲会变得非常差,而且影响代码的美观,所以就产生了Promise对象来解决回调地狱这个令人头疼的问题。
Promise详解
Promise写法
这里我们直接使用ES6的写法
new Promise((reslove,reject)=>{
//异步的一些操作,出现两种状态reslove(),reject()
//两种方法都可以将异步操作的参数传递到后面的then方法和catch方法中
//reslove()走then的回调,reject走then的第二个回调或者直接走catch回调
}).then((success)=>{
//执行成功时,所调用的回调
}).catch((error)=>{
//执行失败时,所调用的回调
})
这里可以看出Promise是一个代理对象,和原先的操作没有直接关系,它通过引入一个回调,避免了更多的回调。
Promise的状态
- 当我们初步new一个Promise对象的时候他属于
pending状态,也就是待定中 - 当操作成功时,Promise会变为
fulfilled,即为操作成功状态 - 当操作失败时,Promise会变为
rejected,即为操作失败状态
Promise状态改变
- Promise状态改变的时候就会触发
.then或者.catch后面的回调 - Promise的状态一旦发生改变之后,不会再继续变化。
两步执行实例
console.log('start')
new Promise((reslove,reject) =>{
setTimeout(()=>{
reslove('hello')
},2000)
}).then((value)=>{
console.log(value)
return new Promise((reslove,reject)=>{
setTimeout(()=>{
reslove('world')
},2000)
})
}).then((value)=>{
console.log(value + ' world')
})
上述代码的执行结果为:
start
hello
world world
已完成的Promise执行then会怎么样
console.log('start')
let promise = new Promise((reslove,reject) =>{
setTimeout(()=>{
console.log('fulfilled')
reslove('hello world')
},2000)
})
setTimeout(()=>{
promise.then((value)=>{
console.log(value)
})
},3000)
已完成的Promise对象可以用变量存储,用在当前Promise作用域的任何地方。
如果.then函数中不返回新的Promise对象会怎么样
console.log('start')
new Promise((reslove,reject) =>{
setTimeout(()=>{
reslove('hello')
},2000)
}).then((value){
console.log(value)
console.log('everyone')
(function(){
return new Promise((reslove,reject)=>{
setTimeout(()=>{
console.log('promise niub')
reslove('biu biu biu')
},2000)
})
}())
return false
}).then((value)=>{
console.log(value + ' world')
})
上述代码的执行结果为:
start
hello
everyone
false world
promise niub
因为return的Promise对象并不在then中,而是在一个自执行函数中,这个时候这个return new Promise会被挂起,然后代码会继续向下执行,等到执行完毕后,再去执行挂起的Promise对象。在Promise中,如果你不直接返回Promise对象,它会直接执行后边的代码,即使返回false也不会阻止代码的继续向下执行。如果.then没有返回值也没有return具体的值,则value会显示undifined。
状态响应函数.then .catch
- 状态响应函数中可以返回新的Promise对象,也可以返回其他值
- 如果返回新的Promise,那么下一级
.then()会在新的Promise状态改变后再执行 - 如果返回的不是Promise对象,那么下一级的
.then()会直接执行 .then()的第二个参数捕获的是上一个Promise对象的错误,.catch()捕获的是Promise整个链式调用的错误,两者优先级根据出现的顺序而定,谁放在前面谁优先级较高
Promise常用函数
Promise.all()
- 接收一个数组为参数
- 数组里可以是别的值,也可以是Promise对象,只有Promise会等待状态改变
- 如果接收的值不是Promise对象,会把接收的值直接传递到下一个状态函数中
- 当所有的子Promise完成,该Promise完成,返回值是所有值的一个数组
- 有任何一个失败,该Promise失败,返回第一个失败的子Promise的结果
Promise.race()
- 类似于Promise.all(),区别在于只要有一个子Promise完成就算完成了
工作中用到的Promise
把回调包装成Promise
getApiData = function(){
return new Promise((reslove,reject)=>{
axios.get('url')
reslove(data)
}).then(data =>{
...
})
}
这样写的话可以保证前一个异步请求完成之后再去进行后边的操作,工作中常用到的应该是这样的处理方式。
基于Promise我目前就写这么多吧,后面我会聊聊ES7中的语法糖,async await,即便有了语法糖也要先学会Promise,希望文章可以帮到大家,我会不断的更新,希望觉得不错的朋友帮忙点个赞!