手写promise

上一篇文章介绍了promise的概念作用及API,这里我们就手鲁代码实现promise

Promise的几个关键问题

开始之前来个灵魂拷问,可能面试会问哟,把这些问题都想清楚是写出promise的关键!!!

1.如何改变 promise 的状态?

改变promise的状态只有3个方法
(1)resolve(value):promiseState pending变成resolved
(2) reject(reason):promiseState pending变成rejected
(3) throw err(抛出异常) promiseState pending变成rejected

2.一个 promise 指定多个成功/失败回调函数, 都会调用吗?

当promise改变对应状态时,都会调用,改变状态后,多个回调函数都会被调用,并不会自动停止

let p = new Promise((resolve, reject) => {  resolve('OK');});
  ///指定回调 - 1
  p.then(value => {  console.log(value); }); //返回undefined,状态变为resolved
  //指定回调 - 2
  p.then(value => { alert(value);});

3.改变promise状态和指定回调函数谁先谁后?

都有可能[由同步异步决定]
先指定回调再改变状态(异步):先指定回调--> 再改变状态 -->改变状态后才进入异步队列执行回调函数

先改状态再指定回调(同步):改变状态 -->指定回调 并马上执行回调

let p = new Promise((resolve, reject) => {
//异步写法,这样写会先指定回调,再改变状态
setTimeout(() => {resolve('OK'); }, 1000);
//这是同步写法,这样写会先改变状态,再指定回调
resolve('OK'); 
});
p.then(value => {console.log(value);}, reason => {})

4.promise.then()返回的新promise的结果状态是什么?

由then()指定的回调函数执行的结果决定
① 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
② 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
③ 如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果

5.promise.catch的异常穿透

当使用promise的then链式调用时,可以在最后指定失败的回调,前面任何操作出了异常,都会传到最后失败的回调中处理
可以在每一个then的第二个回调函数中进行err处理,也可以利用catch的异常穿透特性,在最后用catch去统一处理,两者一起使用时,,err会生效(因为err已经将其处理,就不会再往下穿透),而走不到后面的catch

7.如何中断promise链

我们知道当promise状态改变时,它的链式调用都会生效
如果我们有一个需求:执行到第二个then的时候中断链式调用,如何中断?
在第二个then回调函数中返回一个pedding状态的promise即可


手写Promise实现以上功能点

// executor 执行器函数,2个参数,执行器函数是同步调用都
function Promise(executor){
    // 2个属性
    this.promiseState = 'pending'
    this.promiseResult = null
      //存放then方法的回调函数
    this.callback = []
    const resolve = (data) => {
        if(this.promiseState === 'pending'){
            //修改对象的状态
            this.promiseState = 'fullfilled' //也叫resolved
            //设置对象结果
            this.promiseResult = data

            //异步执行,同步任务执行完成后才执行,这里用宏任务模拟了(有些问题)
            setTimeout(() => {
                this.callback.forEach(item => {
                    //状态改变调用,并将结果传入
                    item.onResolved(data)
                })
            })
        }
    }
   const reject = (data)=>{
       //该条件表示状态只能从pending变为rejected
        if(this.promiseState === 'pending'){
            //修改对象的状态
            this.promiseState = 'rejected'
            //设置对象结果
            this.promiseResult = data
            //异步执行,同步任务执行完成后才执行,这里用宏任务模拟了(有些问题)
           setTimeout(() => {
            this.callback.forEach(item => {
                //状态改变调用,并将结果传入
                item.onRejected(data)
            });
           })
        }
    }
        // try..catch处理throw异常的情况
    try{
        executor(resolve,reject)
    }catch(e){
        //修改promise对象的状态为rejected
        reject(e)
    }
    
}
Promise.prototype.then = function(onResolved,onRejected){
     //判断回调函数参数,如果不是函数设置默认函数值
    if (typeof onResolved !== 'function') {
        onResolved = value => value;
      }
    if (typeof onRejected !== 'function') {
        onRejected = reason => {
        throw reason;
        }
    }

    //返回一个新的promise实例
    return new Promise((resolve,reject) =>{
            //type为onResolved||onRejected
        const detalCallback = (type) => {
            try{
                // 获取回调函数的执行结果
                let result = type(this.promiseResult)
                // 判断类型
                //如果是Promise类型的对象将其自身的状态赋予外层的promise,即将回调函数执行的promise值及状态赋值给外部的promise
                //也就是最终当前then的返回状态由里面回调中的promise的状态决定
                if(result instanceof Promise){
                    result.then(v=>resolve(v),r=>reject(r))
                }else{
                    resolve(result)
                }
            }catch(e){
                //异常,将状态设置为失败
                reject(e)
            }
    }
        //判断promiseState的状态,状态为rejected的时候调用onRejected,为fullfilled的时候调用onResolved
        if(this.promiseState === 'fullfilled') {
            //then 的执行时机在同步任务执行完成后,这里用宏任务完成(存在问题,promise真实的时微任务)
            setTimeout(()=>{
                detalCallback(onResolved)
            })
        }
        if(this.promiseState === 'rejected') {
            setTimeout(()=> {
                detalCallback(onRejected)
            })
        }
        if(this.promiseState === 'pending'){
            //异步的时候,pending状态没变,不能调用回调函数,此时将回调函数存入实例对象的属性中,在resolve和reject函数中调用
            this.callback.push({
                onResolved:() => detalCallback(onResolved),
                onRejected:() => detalCallback(onRejected)
        })
       }
    })
}
Promise.prototype.catch = function(onRejected){
    //ca tch函数为then函数的特例,第一个参数为undefined或者null
    return this.then(undefined,onRejected)
}
//静态方法,直接挂载到构造函数上,将对象等转化为Promise,参数是promise时,返回的是内层promise的状态和结果
Promise.resolve = (value)=>{
    // 判断传入的参数是否为promise对象
    //   1-如果是promise对象:将其状态和结果赋值给外层的promise
    //   2,如果为非promise:状态设置为成功
    return new Promise((resolve,reject) => {
        if(value instanceof Promise){
            value.then(v=>resolve(v),r=>reject(r))
        }else{
            resolve(value)
        }
    })
}
//不同于resolve方法,该方法只需要把传入 参数再次传出,并将状态改为失败
Promise.reject = (reason)=>{
    return new Promise((resolve,reject)=>{
        reject(reason)
    })
}
//传入promise数组,
//1.每当遍历结果是成功时,用计数器记录,当计数器当值等于数组长度,则全部成功,返回成功状态
//2.如果当数组中任意一个promise的执行结果是rejected时,直接返回失败的状态
Promise.all = (promises)=>{
    return new Promise((resolve,reject) => {
        //计数器
        let count = 0
        //存放结果
        let arr = []
        for(let i = 0; i < promises.length; i++ ){
            promises[i].then(v=>{
                count++
                arr[i] = v
                if(count === promises.length){
                    resolve(arr)
                }
            },r=>reject(r))
        }
    })
}
//谁先执行完就返回谁的结果和状态,参数也是promise组成的数组
Promise.race = (promises)=>{
    return new Promise((resolve,reject) => {
        for(let i = 0; i < promises; i++){
            promises[i].then(v => {
                //谁的回调先执行就先返回谁
                resolve(v)
            },
            r=>reject(r))
        }
    })
}

学艺不精,有问题请多多指教

你可能感兴趣的:(手写promise)