浅析promise与自定义promise

42次阅读

共计 2804 个字符,预计需要花费 8 分钟才能阅读完成。

promise 的用法简单介绍一下,我觉得如果有人愿意看这篇文章,对 promise 的用法多多少少也了解;

 new Promise((res, rej) => {
        try{
            执行函数;
            res(data)
        } catch(e){rej(e);
        }}).then(resCb, rejCb).then(cb);

心血来潮,今天去自己试着写了一下 promise。先说下我个人对 promise 的理解

1.promise 从表现形式上看,是将执行函数的返回值通过 resolve 或者 reject 抛出 data,再在 then 函数里面处理 data
2.promise 可以链式调用 then, 上一个 then 的返回值作为下一个 then 中函数的实参

但实际上,promise 并非一定是在 then 里面执行的,尤其是异步的时候,理应在实例函数中执行,才符合我们对单线程的理解。

promise 简单点说分为两部分。一个是实例化 时候,传入的执行函数 另一部分为 then 中传入的回调函数 这个关系就好比 监考老师 学生
如果监考老师 先到了教室,那么自然而然,学生是直接依次进入教室;(实例函数执行较快,超过了 then 的声明)
如果监考老师 在学生们后面到,那么学生们只能按顺序排队在门口等监考老师;(实例函数执行较慢)
也就是说,执行函数和 then 函数的声明,先后顺序并非固定(一般情况下 then 声明先完成)
这个时候就需要一个状态码去判断到底是哪种情况(’default’, ‘resolve’ ,’reject’)
为了方便理解,可以把 resolve 和 reject 看成同一类型
我先直接发代码写注释
时间有限,本次先不考虑 then 中函数 存在异步的问题

// 简述下逻辑:
    //1. 定义一个 state 是用来判断 then 和 实例化时候传入的函数 哪一个先完成
    // 也就是刚刚说的监考老师和学生的问题。默认值为 default, 默认老师没到(实例函数未执行完成)//2. 定义 resolve_ 用来存放 then 中定义的方法,相当于学生排队的过道,便于按顺序执行,reject_同理, 以下不再重复
    //3. 定义 resolveData 用来记录抛出值,也就是 res(data) 中的 data,作为 then 中方法的参数
    //4. 在 res 抛出值的时候,将 state 改成 resolve,相当于表明监考老师到教室了
      // 如果 resolve_队列中已经有定义函数就依次执行它们,相当于如果有学生就进教室。//5.then 方法声明时候,检测状态 state 是不是 default,如果是,说明还没有抛出值,// 相当于监考老师还没到,学生都去排队,加入到 resolve_队列;// 如果状态已经不是 default,那么说明监考老师已经到了,学生不用排队,直接进教室; 也就是方法直接执行
  
new promise_((res, rej) => res(3)).then(data=> {console.log(data);return 6}).then(data => console.log(data))// 3,6

针对实际例子说一下
上面的例子明显就是 res(3) 先执行完成,然后执行 then 的函数
相当于监考老师先到了教室,那么,then 中的定义的函数就应该直接执行

new promise_((res, rej) => setTimeout(() => res(3), 1000).then(data=> {console.log(data);return 6}).then(data => console.log(data))// 3,6

上面的例子明显就是 then 先定义完成,然后 res 才抛出值
相当于监考老师后到了教室,那么,then 中的定义的函数就应该默默排队等待

因为 then 和 实例函数 两者顺序并不确定,所以 then 时候要通过 state 判断实例函数 是否执行完成,
同时,实例函数执行完成抛出值时,也需要检测一下 resolve_队列,判断 then 是否已经声明完成。

class promise_ {constructor(func) {if(typeof func !== 'function'){throw Error('实例化中传参必须为函数');
            return;
        } // 判断下是否传入的是函数,与逻辑无关,直接往下看

        this.state = 'default'; // 用来判断
        this.resolve_ = []; // then 中 reslove 的方法队列,用来接收 resolve 方法
        this.reject_ = []; // then 中的 reject 的方法队列,用来接收 reject 方法
        this.resolveData = null; // resolve 的抛出值
        this.rejectData = null; // reject 的抛出值 

        func(this.resolve.bind(this), this.reject.bind(this)); // 实例化时候传入的函数

    }
    
    then(cb, errCb) {if(typeof cb !== 'function' || (errCb && typeof cb !== 'function')) {throw Error('then 参数,成功回调函数,失败回调函数');
            return;
        } // 日常判断是不是传参正确,和逻辑无关

        switch(this.state) { // 检测一下监考老师来没来教室
            case 'default': this.resolve_.push(cb); this.reject_.push(errCb); break;// 如果监考老师没到场,排队
            case 'resolve': this.resolveData = cb(this.resolveData); break; // 如果监考老师到场,直接进来,因为链式调用,所以执行后把抛出值改一下,方便后面的 then 用
            case 'reject': this.rejectData = errCb(this.rejectData); break;// 如果监考老师到场,直接进来,因为链式调用,所以执行后把抛出值改一下,方便后面的 then 用
            default: break; 
        }

        return this; // 链式调用
    }

    resolve(data) {if(!data) return; // 判断有无参数,和逻辑无关

        this.resolveData = data; // 设定抛出值
        this.state = 'resolve'; // 将状态设置为 resolve,表示监考老师到场了
        while(this.resolve_.length)  // 先进先出,依次执行 then 中函数
            this.resolvedata = this.resolve_.shift()(data);
    }

    reject(data) {if(!data) return;

        this.rejectData = data;
        this.state = 'reject';
        while(this.reject_.length) 
            this.rejectData = this.reject_.shift()(data);
    }

}


正文完
 0