一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
🤚什么是Promise
- Promise是js中异步编程的新解决方案
- 从语法上来说: Promise是一个构造函数
- 从功能上来说: Promise对象用来封装一个异步操作并可以获取其 成功/失败 的结果值
❓为什么要用Promise
-
支持链式调用, 可以解决回调地狱问题
-
方便阅读&理解
🚀了解Promise
Promise是个构造函数,
const p = new Promise()
我们在创建Promise实例对象时,需要一个函数类型的值作为参数
const p = new Promise(() => {})
并且这个函数还有2个形参 (当然形参嘛可以自己定义名字,a,b什么的都可以,但是一般叫resolve reject)
const p = new Promise((resolve, reject) =>{})
这个resolve和reject也都是函数类型的值,当异步任务成功的时候调用resolve,失败则调用reject
Promise可以包裹一个异步操作,我们就是把异步操作放在里面的
下面我写了一个抽随机数的事件,小于等于30为成功,反之
// 封装一个随机数
function randomNum(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min)
}
const p = new Promise((resolve, reject) => {
setTimeout(() => {
let num = randomNum(1, 100)
num <= 30 ? resolve(num) : reject(num)
}, 1000)
})
调用resolve()时会将Promise的状态设为成功fulfilled
调用reject()时会将Promise的状态设为失败rejected
而实例的p有一个.then方法,他执行时要接收2个参数,这2个参数还是函数类型值
p.then((value) => {
alert('成功-->数字为'+value)
}, (reason) => {
alert('失败-->数字为'+reason)
})
then中第一个函数是对象成功时的回调,第二个是失败时的回调
🎈Promise状态
继续刚刚的实例对象,刚刚说可以改变它的状态,那么它的状态究竟是什么呢?
打印他
可以看到,他就Promise的一个属性
它是有三种状态的
- pending 待定
- fulfilled 成功
- rejected 失败
Promise的状态只能改变一次,无论成功还是失败,他都会返回一个结果
这个状态只能由pending -> fulfilled
或者pending -> rejected
🚗Promise工作流程
😎exceutor函数
刚刚所说的const p = new Promise(参数)在创建实例对象时需要一个函数作为参数。
而那个函数就是executor()执行器函数 ,里面有两个形参是(resolve,reject) => {}
这个resolve和reject也是函数,是内部定义的,成功/失败时调用
注意,这个executor()在Promise中是同步执行的,而executor()里是异步操作
👩.then方法
.then(onResolved, onRejected) => {}
- onResolved也是个函数,执行的是Promise成功时的回调
- onRejected函数,失败时回调
👨.catch方法
(onRejected)=> {}
这个是和.then的第二个参数一样,用来指定rejected回调
不过它还有另外一个作用:在执行resolve的回调(也就是then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。
const p = new Promise((resolve, reject) => {
resolve('success')
})
p.then(value => {
console.log('then的第一个回调函数', value);
console.log(niubi, value) // 这个niubi是未定义的
}).catch(err => {
console.log(err, '欢迎来到catch')
})
跑起来就是这样
then方法也进去了,catch方法也进去了,并把错误的原因传到了catch中
❤️resolve&reject方法
Promise.resolve 方法:(value) => {}
-
value:成功的数据或Promise对象
-
返回一个成功或失败的Promise对象
如果传入的参数是一个非Promise类型对象,则返回结果为Promise成功对象
let p1 = Promise.resolve('123')
console.log(p1)
如果传入的是一个Promise对象,则参数的结果决定了resolve的结果🔻
let p2 = Promise.resolve(new Promise((resolve,reject) => {
resolve('ahhhh')
}))
console.log(p2)
let p2 = Promise.resolve(new Promise((resolve,reject) => {
// resolve('ahhhh')
reject('ahhhh')
}))
console.log(p2)
我成功的值是'ahhhh'它返回的成功回调值也是'ahhhh',
我失败时的值是'ahhhh',他返回的失败回调也就是'ahhh'
Promise.reject 方法:(reason) => {}
- reason:失败的原因
- 返回一个失败的Promise对象
let p1 = Promise.reject('123')
console.log(p1)
而另一种,即使传入的是成功的Promise对象,那得出的结果还是失败
let p1 = Promise.reject(new Promise((resolve, reject) => {
resolve('ok')
}))
console.log(p1)
它失败的结果是我们传入的Promise成功的对象。
总结就是:你传什么都是失败
😒all方法
-
Promise.all(promises)接收一个参数,这个参数一般为Promise组成的一个数组 -
返回结果:一个新的Promise对象,这个新Promise对象的状态由数组当中它们的状态据决定。只要数组中所有的Promise都成功才成功,只要有一个失败就直接失败
-
返回成功结果:是它们每一个Promise成功结果组成的数组
-
返回失败结果:是失败那个Promise对像,它失败的结果。一旦有失败,后面也就不会执行了
let p1 = new Promise((resolve,reject) => {resolve('ok')})
let p2 = new Promise((resolve,reject) => {resolve('success')})
let p3 = new Promise((resolve,reject) => {resolve('yes')})
let p4 = new Promise((resolve,reject) => {resolve('yeah')})
const result = Promise.all([p1,p2,p3,p4])
console.log(result)
let p1 = new Promise((resolve,reject) => {resolve('ok')})
let p2 = new Promise((resolve,reject) => {reject('success')})
let p3 = new Promise((resolve,reject) => {reject('yes')})
let p4 = new Promise((resolve,reject) => {resolve('yeah')})
const result = Promise.all([p1,p2,p3,p4])
console.log(result)
🍕race方法
-
Promise.race(promises)接收一个参数,这个参数和上面一样 = =、 -
返回结果:一个新的Promise对象 , 这个新的Promise的状态是由第一个改变状态的Promise决定
总结就是:类似赛跑,谁先改变状态,谁就决定race的返回结果
let p1 = new Promise((resolve,reject) => {resolve('ok')})
let p2 = new Promise((resolve,reject) => {reject('success')})
let p3 = new Promise((resolve,reject) => {reject('yes')})
let p4 = new Promise((resolve,reject) => {resolve('yeah')})
const result = Promise.race([p1,p2,p3,p4])
console.log(result)
这个代码不需要思索,肯定是ok
改进下试试吧
let p1 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('ok')
}, 100);
})
let p2 = new Promise((resolve,reject) => {resolve('success')})
let p3 = new Promise((resolve,reject) => {resolve('yes')})
let p4 = new Promise((resolve,reject) => {resolve('yeah')})
const result = Promise.race([p1,p2,p3,p4])
console.log(result)
❓Promise的一些关键问题
如何修改对象的状态
-
resolve():pending --> fulfilled
-
reject():pending --> rejected
-
throw: pending --> rejected
能否执行多个回调
当它的状态发生改变,那么它对应的回调 都会执行
then方法返回由什么决定
问题:Promise返回的then方法也是Promise,那么这个then方法的结果状态由什么决定?
答:由then的回调函数执行的结果决定。
- 如果是throw抛出错误 ----> 变成失败
- 如果是非Promise类型对象 ----> 成功
- 如果是Promise对象 ---> 由这个Promise状态决定
链式调用
这里p1里面调用的是resolve(),所以会执行p1.then()
而p1.then也是一个Promise对象,内部也是调用resolve()
那么第二个.then执行的是p1.then的成功回调
就打印出“success”
这个又多加了个.then
最后一个.then执行的是它上面那个的成功回调
可是上面那个return的是空的,所以就打印了undefined
异常穿透
-
在Promise链式调用中,可以在最后指定失败回调
-
前面任何操作出现了异常都会传到最后失败的回调中处理
这个任务由最终的catch执行。正常来说我们会在第一个then里面用catch方法处理异常,但是由于异常穿透特性,下边的then方法不需要指定失败回调,它会在最后的catch处理异常
如何中断Promise链
我只知道一种方式,就是返回pending状态的Promise
<script>
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK')
}, 1000)
})
p1.then(value => {
console.log(111)
}).then(value => {
console.log(222)
}).then(value => {
console.log(333)
})
</script>
中断它 🔻🔻🔻
✍️手写Promise
这个Promise没有写 race 和 all 方法
- Promise状态只能修改一次
- then方法
- 异步
- 多回调
- 同步状态
- 异步状态
- 完善then方法
完整代码
class Promise{
// 构造方法
constructor(executor){
// 同步调用【执行器函数】
this.PromiseState = 'pending'
this.PromiseResult = null
this.callbackList = []
// 因为下面函数里的this指向的是window,所以这里需要保存this变量
const self = this
// resolve函数
function resolve(data){
// 作用:让Promise状态只能改一次
if (self.PromiseState !== 'pending') return
// 改变状态, 设置对象结果值
self.PromiseState = 'fulfilled'
self.PromiseResult = data
// 调用成功回调的函数们-异步的执行
self.callbackList.forEach(item => {
item.onResolved(data)
})
}
// reject函数
function reject(data){
if (self.PromiseState !== 'pending') return
self.PromiseState = 'rejected'
self.PromiseResult = data
self.callbackList.forEach(item => {
item.onRejected(data)
})
}
// 抛出异常改变状态
try {
// 执行器函数
executor(resolve, reject)
}catch(e){
reject(e)
}
}
// then方法
then(onResolved, onRejected){
const self = this
// 判断回调函数参数
// 异常穿透功能
if (typeof onRejected !== 'function') {
onRejected = reason => {
throw reason
}
}
// 值传递功能
if (typeof onResolved !== 'function') {
onResolved = value => value
}
//then返回的是一个Promise对象
return new Promise((resolve, reject) => {
// 封装函数callback
function callback(type){
try{
// 拿到回调函数的执行结果
let result = type(self.PromiseResult)
// 判断它返回的对象
if (result instanceof Promise) {
// 若是promise对象
result.then(v => {
resolve(v)
}, r => {
reject(r)
})
} else {
// 结果的对象状态为成功
resolve(result)
}
}catch(e){
reject(e)
}
}
if (this.PromiseState === 'fulfilled') {
callback(onResolved)
}
else if (this.PromiseState === 'rejected') {
callback(onRejected)
}
else if (this.PromiseState === 'pending') {
// 处理异步。 实现多回调执行
// 先把回调函数保存起来
this.callbackList.push({
onResolved: function(){
callback(onResolved)
},
onRejected: function(){
callback(onRejected)
}
})
}
})
}
// catch方法
catch(onRejected){
return this.then(undefined, onRejected)
}
// resolve方法
static resolve(value){
// 返回Promise对象
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(v => {
resolve(v)
}, r => {
reject(r)
})
} else {
resolve(value)
}
})
}
// reject方法
static reject(reason){
return new Promise((resovle, reject) => {
reject(reason)
})
}
}