Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

手写Promise #3

Open
janeLLLL opened this issue Aug 25, 2020 · 0 comments
Open

手写Promise #3

janeLLLL opened this issue Aug 25, 2020 · 0 comments

Comments

@janeLLLL
Copy link
Owner

[toc]

Promise核心逻辑实现

示例

//index.js
let promise = new Promise((resolve,reject) => {
    resolve('成功')//成功值
    reject('失败')
})

promise.then(value => {
    console.log(value)
}, reason => {
    console.log(reason)
})
//newPromise.js

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class NewPromise {
    constructor(executor) {
        executor(this.resolve,this.reject)
    }
    //promise状态
    status = PENDING
    value = undefined
    reason = undefined
    //值默认没有
    resolve = value => {
        //如果状态不是等待,阻止程序向下执行
        if(this.status !== PENDING)return
        this.status = FULFILLED
        this.value = value
    }
    //使用箭头函数的原因:直接调用一个普通函数,函数里面的this指向是undefined的
    reject = reason => {
        if(this.status !== PENDING)return
        //将状态更改为失败
        this.status = REJECTED
        this.reason = reason
    }
    //判断promise的状态,返回回调函数,需要传递value和reason
    then(successCallback,failCallback){
        //判断状态
        if(this.status === FULFILLED){
            successCallback(this.value)
        }else if(this.status === REJECTED){
            failCallback(this.reason)
        }
    }
}

module.exports = NewPromise

总结

  1. Promise 就是一个类,在执行这个类的时候,需要传递一个执行器进去,执行器会立即执行

    ...
    constructor(executor){
    	executor(this.resolve,this.reject)
    }
    //构造函数接收执行
    ...
  2. Promise 中有三种状态,分别为成功 fulfilled、失败 rejected、等待 pending

    一旦状态确定就不可更改

graph LR
pending --> fulfilled
pending --> rejected
Loading
  1. resolve和reject函数是用来更改状态的
resolve: fulfilled
reject: rejected
  1. then方法内部做的事情就判断状态,如果状态是成功,调用成功的回调函数,如果状态是失败。
    调用失败回调函数 then方法是被定义在原型对象中的

    then作用:判断promise的状态,返回回调函数,需要传递value和reason

  2. then成功回调有一个参数value,表示成功之后的值,then失败回调有一个参数reason,表示失败后的原因

在Promise类中加入异步逻辑

示例,在执行器中加入异步代码

//index.js
let promise = new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve('成功')
    },2000)
})

promise.then(value => {
    console.log(value)
}, reason => {
    console.log(reason)
})
//newPromise.js

class NewPromise {
    ...
    successCallback = undefined
    failCallback = undefined
	//默认是undefined
    ...
    resolve = value => {
        //如果状态不是等待,阻止程序向下执行
        if(this.status !== PENDING)return
        this.status = FULFILLED
        this.value = value
        //判断成功回调是否存在,如果存在 调用
        this.successCallback && this.successCallback(this.value)//在更改状态函数里执行成功/失败回调
    }
    //直接调用一个普通函数,函数里面的this指向是undefined的
    reject = reason => {
        if(this.status !== PENDING)return
        //将状态更改为失败
        this.status = REJECTED
        this.reason = reason
        //判断成功回调是否存在,如果存在 调用
        this.failCallback && this.failCallback(this.reason)//在更改状态函数里执行成功/失败回调
    }
    
     then(successCallback,failCallback){
        //判断状态
        if(this.status === FULFILLED){
            successCallback(this.value)
        }else if(this.status === REJECTED){
            failCallback(this.reason)
        }else{
            //等待,临时存储成功和失败回调
            //将成功回调和失败回调存储起来
            this.successCallback = successCallback
            this.failCallback = failCallback
        }
    }
    ...
}

实现then方法多次调用添加多个处理函数

当有多个then时,会有多个成功和失败回调,此时应该将保存的回调函数变成一个数组,在状态更改时依次取出并且传递一个成功值/失败结果给成功回调/失败回调

//index.js
promise.then(value => {
    console.log(value)
})

promise.then(value => {
    console.log(value)
})

promise.then(value => {
    console.log(value)
})
//将保存的回调函数变成一个数组
successCallback = []
failCallback = []
...
//this.successCallback && this.successCallback(this.value)
while(this.successCallback.length){
            this.successCallback.shift()(this.value)
    //shift()方法会移除并回传阵列的第一个元素
    }
...
{
    this.successCallback.push(successCallback)
    this.failCallback.push(failCallback)
}
...

then方法的链式调用

  1. 当promise对象发生了链式调用时,应当在then方法里添加一个promise对象返回,以便于下一次then再次调用这个promise对象
//index.js
let promise = new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve('成功')
    },2000)
})

promise.then(value => {
    console.log(value)
    return 100
    //链式调用then方法
}).then(value => {
    console.log(value)
    //value = 100
})
//newPromise.js
    then(successCallback, failCallback) {
        let promise2 = new NewPromise((resolve,reject) => {
            if (this.status === FULFILLED) {
                let x = successCallback(this.value)
                resolve(x)
                //传递的时一个普通值x的时候,调用resolve()方法,把这个普通纸传递给下一个promise2对象
            } else if (this.status === REJECTED) {
                failCallback(this.reason)
            } else {
                this.successCallback.push(successCallback)
                this.failCallback.push(failCallback)
            }
        })
        return promise2
        //调用了then方法会返回一个promise,以便于下一次then可以继续链式调用
    }
  1. 当链式调用的上一个then return的值不是一个普通值而是一个promise对象时

    • 判断 x 的值是普通值还是promise对象

    • 如果是普通值,直接调用resolve

    • 如果是promise对象,查看promsie对象返回的结果

    • 再根据promise对象返回的结果,决定调用resolve 还是调用reject

    //index.js
    let promise = new NewPromise((resolve,reject) => {
        resolve('成功')
    })
    
    function other(){
        return new NewPromise((resolve,reject) => {
            resolve('other')
        })
    }
    
    promise.then(value => {
        console.log(value)
        return other()//other是一个promise对象
    }).then(value => {
        console.log(value)
        //value = other
    })
    class NewPromise{
        ...
        then(successCallback, failCallback) {
            let promise2 = new NewPromise((resolve,reject) => {
                if (this.status === FULFILLED) {
                    let x = successCallback(this.value)
                    resolvePromise(x,resolve,reject)
                    //传递的时一个普通值x的时候,调用resolve()方法,把这个普通纸传递给下一个promise2对象,这里使用一个resolvePromise()方法去判断这个x是普通值还是promise对象
                } else if (this.status === REJECTED) {
                    failCallback(this.reason)
                } else {
                    this.successCallback.push(successCallback)
                    this.failCallback.push(failCallback)
                }
            })
            return promise2
        }
        ...
    }
    
        
    function resolvePromise(x,resolve,reject){
        if(x instanceof NewPromise){
            // x.then(value => resolve(value),reason => {reason})//查看状态
            x.then(resolve,reject)
        }else{
            resolve(x)
        }
    }

then方法链式调用识别Promise对象自返回

当then返回了当前的promise对象时,需要识别是否是自对象。

解决:在resolvePromise中判断当前传值x是否为当前priomise对象

//index.js
let p1 = promise.then(value => {
    console.log(value)
    return p1
})
p1.then(value=>{
    console.log(value)
},reason => {
    console.log(reason)
})
//promise的循环调用
function resolvePromise(promise2, x,resolve,reject){
    if(promise2 === x){
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if(x instanceof NewPromise){
        // x.then(value => resolve(value),reason => {reason})//查看状态
        x.then(resolve,reject)
    }else{
        resolve(x)
    }
}

捕获/处理错误

//在执行器中进行错误捕获
class NewPromise{
constructor(executor) {
        try{
            executor(this.resolve, this.reject)
        }catch(e){
            this.reject(e)
        }
    }
...
}

注意,上一个then方法的错误在下一个then中捕获到

同理,不止要在执行器中进行错误捕获,在状态改变之后进行也要进行错误捕获

then(successCallback, failCallback) {
        let promise2 = new NewPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                        let x = successCallback(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) {
                try {
                    failCallback(this.reason)
                } catch (e) {
                    reject(e)
                }
            } else {
                this.successCallback.push(()=>{
                    successCallback()
                })
                this.failCallback.push(() => {
                    failCallback()
                })
                //要对回调函数进行处理
            }
        })
        return promise2
    }

将then方法的参数变成可选参数

当then不传递任何参数时,最新一个then获取的value还是上一个最新then传递的参数

promise
    .then()
    .then()
    .then(value => console.log(value))

//相当于
promise
    .then(value => value)
    .then(value => value)
//一层层向后进行传递相同的内容
    .then(value => console.log(value))
//NewPromise.js
then(successCallback, failCallback){
	successCallback = successCallback ? successCallback : value => value
    failCallback = failCallback ? failCallback : reason => reason
}

Promise.all()

  1. 返回值是Promise对象
  2. 参数为数组,数组中可以传递普通值和promise对象
  3. 可以解决异步并发,允许按照异步API调用顺序得到异步API的执行结果
  static all (array) {
    let result = [];
    let index = 0;
    return new MyPromise((resolve, reject) => {
      function addData (key, value) {
        result[key] = value;
        index++;
        if (index === array.length) {
          resolve(result);
        }
      }
      for (let i = 0; i < array.length; i++) {
        let current = array[i];
        if (current instanceof MyPromise) {
          // promise 对象
          current.then(value => addData(i, value), reason => reject(reason))
        }else {
          // 普通值
          addData(i, array[i]);
        }
      }
    })
  }

promise.resolve()

  static resolve (value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise(resolve => resolve(value));
      //普通值:创建promise对象,传递一个执行器,使用resolve方法将value进行返回
  }

Promise.finally()

  1. 无论当前Promise对象的执行结果是成功还是失败,finally()方法当中的回调函数始终会被执行一次

  2. 在finally()方法的后面可以链式调用then方法来拿到Promise对象最终返回的结果

  3. 不是静态方法,要定义在原型对象身上

    finally (callback) {
        return this.then(value => {
          return MyPromise.resolve(callback()).then(() => value);
          //需要借助resolve,不管是普通值还是promise对象,都使用resolve转化为promise对象
          //再使用then地成功回调方法返回一个value
          //这样就可以等待callback()的返回值,再去执行return value
          //避免setTimeout没走完就返回了value
        }, reason => {
          return MyPromise.resolve(callback()).then(() => { throw reason })
        })
      }
    
    //index.js
    function p1 () {
      return new MyPromise(function (resolve, reject) {
        setTimeout(function () {
          resolve('p1')
        }, 2000)
      })
    }
    function p2 () {
      return new MyPromise(function (resolve, reject) {
        // reject('失败')
        resolve('p2 finally');  
      })
    }
    
    
    p2().finally(()=> {
      console.log('finally')
      return p1()
    }).then(value => {
      console.log(value)
      //没等两秒之后就已经输出了
    },reason => {
      console.log(reason)
    })

    Promise.catch()

    链式调用catch去处理reject()失败的情况

      catch (failCallback) {
        return this.then(undefined, failCallback)
        //不传递成功回调,只传递失败回调
        //return便于之后使用promise的其它方法
      }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant