拉勾大前端的笔记,仅作为学习记录
从使用的角度往前推Promise的原理
- Promise 是一个类,在执行类的时候,需要传入一个执行器,执行器会立即执行
- Promise 中有三种状态 分别为 成功 fulfilled、失败 rejected,等待 pending
- pending为初始化,可以变成fulfilled 或者 rejected,
- 状态一旦被改变就不能更改
- resolve函数和reject函数用来改变Promise状态
- resolve -> fulfilled
- reject -> rejected
- then方法的作用就是判断状态,如果fulfilled 就执行成功回调,如果rejected 就执行失败回调,then方法是定义在原型对象中的
- then成功回调有一个参数表示成功回调的值,then失败回调也有个参数表示失败回调的原因
- 如果执行器有异步执行的情况,需要在then方法里面把两个回调函数缓存,在调用resolve或者reject的时候再去调用
7.同一个promise的then方法可以多次调用,每一个then方法传递的回调函数都是要被执行的,也是分两种情况去处理- 同步情况
- 异步情况
8.then方法是可以被链式调用的,后面then方法的回调函数是上一个then方法回调函数的返回值 - 如何实现then方法的链式调用
- 返回promise对象
- 注意当前的回调函数不能返回上一个then返回的promise对象,会报错 - 把上一个then的返回值传递给下一个then
1. 判断 x 的值是普通值还是Promise对象
2. 如果是普通值 直接调用 resolve
3. 如果是promis对象,查看promise对象的返回结果
4. 再根据promise对象返回的结果 决定调用resolve 还是 reject
9.错误捕获 - 对执行器进行捕获
- 当then方法发生错误时,该错误要在下一个then的reject捕获到
const promise = new Promise((resolve,reject)=>{
resolve('成功')
reject('失败')
})
promise.then( value =>{
// fulfilled 时候执行
},reason =>{
// rejected 时候执行
})
promise.then( value =>{
// 同一个promise方法调用了两次then
})
// 把上一个then作为下一个then的返回
const promise1 = promise.then(value => {
return promise1
})
实现代码
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
constructor( executor ){
// 捕获执行器错误
try{
executor(this.resolve,this.reject)
}catch(e){
this.reject(e)
}
}
status = PENDING
value = undefined
reason = undefined
scuessCallback = []
failCallback = []
resolve = (value) =>{
if(this.status !== PENDING) return
this.status = FULFILLED
this.value = value
// this.scuessCallback && this.scuessCallback(this.value)
while(this.scuessCallback.length) this.scuessCallback.shift()()
}
reject = (reason) =>{
if(this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
// this.failCallback && this.failCallback(this.reason)
while(this.failCallback.length) this.failCallback.shift()()
}
then(scuessCallback,failCallback){
// 链式调用需要返回一个Promise
const promise2 = new MyPromise((resolve,reject)=>{
if(this.status === FULFILLED){
// 同步执行在内部并不能获取到promise2,因为promie2要等new MyPromise这部分同步代码执行完才会生成,所以把对promise2的操作放在异步代码中
setTimeout(()=>{
try{
const x = scuessCallback(this.value)
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
},0)
}else if(this.status === REJECTED){
setTimeout(()=>{
try{
const x = failCallback(this.reason)
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
},0)
}else {
// 当前为pending状态
this.scuessCallback.push(()=>{
setTimeout(()=>{
try{
const x = scuessCallback(this.value)
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
},0)
})
this.failCallback.push(()=>{
setTimeout(()=>{
try{
const x = failCallback(this.reason)
resolvePromise(promise2,x,resolve,reject)
}catch(e){
reject(e)
}
},0)
})
}
})
return promise2
}
}
function resolvePromise(promise2,x,resolve,reject) {
// 判断 x 的值是普通值还是Promise对象
// 如果是普通值 直接调用 resolve
// 如果是promis对象,查看promise对象的返回结果
// 再根据promise对象返回的结果 决定调用resolve 还是 reject
if(promise2 === x){
return reject(new TyppeError('Chaing cycle detected for promise # <Promise>'))
}
if( x instanceof MyPromise){
// 查看x是不是MyPromise 的实例对象
// x.then(value => resolve(value),reason => reject(reason));
// 简写
x.then(resolve,reject)
}else{
// x是普通值
resolve(x)
}
}
补充代码
将then方法的参数变成可选参数
promise
.then()
.then(value => value) // 传递控制相当于value => value,也就是直接把value返回了
.then(value => console.log(value))
// 在实现函数的then方法中加入默认值
then(scuessCallBack, failCallback){
scuessCallback ? scuessCallback: value => value
failCallback ? failCallback: reason => { throw reason }
}
Promise.all方法实现
- 解决异步并发问题的
- all方法允许我们通过异步代码调用的顺序得到异步代码的结果
- all方法也会返回一个promise对象
- 如果promise传递的数组中有一个Promise执行失败,返回的Promise即为失败
- Promise传递的数组中,所有执行成功,返回的Promise才是成功
// 原生Promise.all的调用
const p1 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve('p1')
},2000)
})
const p2 = new Promise((resolve,reject)=>{
resolve('p2')
})
Promise.all(['a',p1(),p2()]).then(function(result) {
console.log(result) // ['a','p1','p2']
})
// promise all 的实现 ,在myPromise里面加上静态方法all
static all(array){
const result = []
const index = 0
return new Promise((resolve,reject)=>{
function addData(key,value) {
result[key] = value
index++
if(index === array.length){
resolve(result)
}
}
for(let i =0 ;i <= array.length ; i++){
if(array[i] instanceof MyPromise){
array[i].then(value => addData(i,value), reason => reject(reason))
// array[i]是promis对象
}else{
addData(i,array[i])
// array[i] 是普通对象
}
}
})
}
Promise.resolve方法的实现
static resolve(value){
if (value instanceof MyPromise) return value
return new MyPromise(resolve => resolve(value))
}
finally方法的实现
- 无论promise执行结果是成功还是失败,finally都会被执行一次
- finally方法后面还要链式调用then方法
// 在MyPromise 添加内部方法
finally(callback){
return this.then(value => {
return MyPromise.resolve(callback()).then(value => value)
}, reason => {
return MyPromise.resolve(callback()).then(reason => {throw reason})
})
}
catch方法的实现
- 在内部调用then方法,成功的时候传递undefined,失败的时候传递出去
catch( failCallback) {
return this.then(undefined,failCallback)
}