学习Promise

155 阅读3分钟

promise的使用

var p1 = new Promise(function(resolve, reject){ 
    resolve(1); 
    // reject(0);
})

p1.then(data => {
    console.log(data)
})

promise核心逻辑

promise核心就是一个class类,这个类需要一个执行器进去立即执行。 另外promise需要三个状态 pending,fulfilled,rejected。

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class myPromise {
    constructor(executor){ 
        executor(this.resolve,this.reject)
    }
    // promise 状态
    status = PENDING
    // 成功之后的值
    value= undefined
    // 失败之后的原因
    err= undefined
    
    resolve= value=>{
        // 如果状态不是等待 阻止程序继续执行
        // 将状态改为成功
        if(this.status !== PENDING) return
        this.status= FULFILLED
        // 保存成功的值,then函数要拿到
        this.value= value
    }
    reject= reason=>{
        if(this.status !== PENDING) return
        this.status= REJECTED
        // 保存失败原因
        this.err= reason
    }

    then(successCallback,failCallback){ //接收两个回调函数 成功 失败
        if(this.status === FULFILLED){
            successCallback(this.value)
        }else if(this.status === REJECTED){
            failCallback(this.err)
        }

    }
}

module.exports= myPromise

resolve 和 reject方法在执行的时候各自保存成功的val值和失败的err原因,在之后then方法会用到
在使用promise调用then方法的时候传入了fn,then方法内部会判断promise的状态是fulfilled还是rejected来决定执行的fn是成功回调还是失败回调

当promise状态是pending的时候

let promise= new MyPromise((resolve,reject)=>{
    setTimeout(()=>{类型
        resolve("成功...")
    },5000)
    // resolve("成功")
})

当resolve或reject是异步执行的时候,此时promise的status还是pending,我们并不能知道then方法到底需要执行成功回调还是失败回调,所以我们在调用then方法的时候,then(successCallback,failCallback)方法内部需要将这两个回调方法储存起来,需要注意的是,因为then方法支持多次调用,所以储存回调方法的容器需要是一个array类型

// 成功回调
successCallback= []
// 失败回调
failCallback= []
then(successCallback,failCallback){ //接收两个回调函数 成功 失败
    if(this.status === FULFILLED){
        successCallback(this.value)
    }else if(this.status === REJECTED){
        failCallback(this.err)
    }else{
        // 执行器是异步操作时,status还是pending
        this.successCallback.push(successCallback),
        this.failCallback.push(failCallback)
    }

}

之后当resolve或者reject方法被调用的时候,那时promise的status以及重新赋值,我们已经知道了状态,就可以从容器数组中取出需要执行对应的成功回调或者失败回调

resolve= value=>{
    // 如果状态不是等待 阻止程序继续执行
    // 将状态改为成功
    if(this.status !== PENDING) return
    this.status= FULFILLED
    // 保存成功的值,then函数要拿到
    this.value= value
    while(this.successCallback.length) this.successCallback.shift()(this.value)
}
reject= reason=>{
    if(this.status !== PENDING) return
    this.status= REJECTED
    // 保存失败原因
    this.err= reason
    while(this.failCallback.length) this.failCallback.shift()(this.err)
}

详解then的链式调用

上面提到then方法接收两个参数 successCallbackfailCallback,两个回调方法,当resolve的时候执行成功回调,reject执行失败回调
但如此还不能达到链式调用的效果,接下来来看看实现链式调用的核心逻辑

  1. then方法执行结束需要返回一个新的promise对象
  2. 返回新的promise对象需要接收上一个promise对象返回的结果,也就是需要把 successCallback(this.value)传递给新的promise对象的resolve
  3. 判断上一次promise对象的返回值是普通值还是promise对象,普通值则直接resolve,如果是promise则需要另外判断其返回结果再决定走resolve还是reject
function resolvePromise(x, resolve,reject){
    if(x instanceof MyPromise){
        // promise对象
        x.then(resolve,reject)
    }else{
        // 普通值
        resolve(x)
    }
}

定义resolvePromise方法来实现上述第三点,这个方法接收所需返回的新的promise对象,通过instanceof判断这个对象是否继承自myPromise
在then方法执行时我们new MyPromise得到新的promise

then(successCallback,failCallback){ //接收两个回调函数 成功 失败
    // 定义一个新的promise对象实现链式调用
    let newPromise= new MyPromise((resolve,reject)=>{
        if(this.status === FULFILLED){
            let x= successCallback(this.value)
            // resolve(x)
            resolvePromise(x,resolve,reject)
        }else if(this.status === REJECTED){
            failCallback(this.err)
        }else{
            // 执行器是异步操作时,status还是pending
            this.successCallback.push(successCallback),
            this.failCallback.push(failCallback)
        }
    })
    return newPromise

}