JS基础

手写promise

2020-09-04  本文已影响0人  小宇cool

1. 为什么需要Promise?

我们通常都会说为了解决回调地狱,大家都知道在做前端开发时,最让人头痛的就是处理异步请求, 在请求的成功的回调函数里面进行写函数, 长此以往形成了回调地狱

function load(){
    function init(res,callback){
        callback(res + 10)
    }
    function redner(res2,callback){
        callback(res2+10)
     }
    setTimeout((res) =>{
        init(res,(res2) =>{
            redner(res2,(res3)=>{
                console.log(res3);// 30
            })
          
       })
    }, 2000, 10);
}
load()
  

上面的代码就是一个回调地狱,存在着多层嵌套的的问题, 如果层级还多一点, 那么代码会变得极其难以维护,

1.1 promise的简单使用

上面的代码通过如果使用promise就会变得简洁清晰很多.

 function load() {
        return new Promise((reslove, reject) => {
            setTimeout((res) => {
                reslove(res)
            }, 2000, 10);
        })
    }
    load()
    .then(res => {
        return res + 10
    })
    .then(res => {
        return res + 10
    })
    .then(res =>{
        console.log(res);// 30
    })

2. 怎么实现一个promise?

Promise是一个类,类中需要传入一个executor执行器, 执行器会默认执行,就像下面这样打印出1

new Promise(()=>{
    console.log(1)
})
  1. 首先介绍Promise的三种状态
  1. promise的状态一旦从pending状态改变为成功或失败就不能在改变

  2. 每个promise实例都有一个then方法, 分别是成功和失败的回调;

  3. promise内部会提供两个方法, 注意不是原型上的,这两个方法是给用户的,用来改变promise状态.

了解了上面的基本几点后, 我们可以写成一个基本的promise;

1. 同步promise
class _Promise{
    static  PENGIND = 'PENDING';// 准备状态常量
    static  FULFILLED = 'FULFILLED';// 成功状态
    static REJECTED = 'REJECTED';//拒绝状态
    constructor(executor){
        this.status = _Promise.PENGIND;// 定义promise 状态, 默认为 准备状态
        this.value = undefined; // 保存改变状态时传递的值
        // //用于class 默认使用严格模式, 所有需要手动绑定this
        const resolve = _Promise.reslove.bind(this)
        const reject = _Promise.reject.bind(this);
        try {
            executor(resolve,reject)// 传入两个方法
        } catch (error) {// 当executor报错时把 错误值传递给拒绝方法
            reject(error)
        }
      
    }
     reslove(value){
        // 当状态为等待状态时改变promise实例状态为 成功
        if(this.status ===  _Promise.PENGIND){
            this.status = _Promise.FULFILLED
            this.value = value;
        }
    }
     reject(reason){
     // 当状态为等待状态时改变promise实例状态为拒绝
        if(this.status === _Promise.PENGIND){
            this.status = _Promise.REJECTED
            this.value = reason;
        }
    }

    then(onfulfilled=()=>{},onRejected=()=>{}){// 给then方法内的两个回调函数添加默认值
        //  如果传递参数的类型不是函数, 就抛出一个错误
       if(typeof onRejected !== "function" ||typeof onRejected !== "function"){
           throw new Error('The argument type must be a function')
       }
       //当Promise实例状态为成功时调用onfulfilled函数, 并传入实例对象上的value值
        if(this.status === _Promise.FULFILLED){
            onfulfilled(this.value)
        }
        if(this.status === _Promise.REJECTED){
            onRejected(this.value)
        }
    }
}
2. 异步promise

promise 状态只能在 reslove状态 或者 reject的时候改变, 同步代码执行到then回调的时候promise状态是pending,明显是不符合我们的期望的.这里我们可以使用发布订阅模式,发布订阅模式简单来说就是我们将现在要做的事情.放到某个时间点在进行执行.

思路:我们可以在实例对象上定义两个数组用来保存then调用时的回调函数, 当状态改变方法调用时, 我们从实例对象上拿到这两个数组里的回调函数进行遍历, 对其进行调用同时传递参数

class _Promise{
    static  PENGIND = 'PENDING';// 准备状态常量
    static  FULFILLED = 'FULFILLED';// 成功状态
    static REJECTED = 'REJECTED';//拒绝状态
    constructor(executor){
        this.status = _Promise.PENGIND;// 定义promise 状态, 默认为 准备状态
        this.value = undefined; //     保存状态成功时传递的值
        this.reason = undefined; // 保存状态拒绝时传递的值
        this.onResloveCallbackS = [];  // 保存状态成功的回调函数
        this.onRejectEdCallbackS = []; //保存状态拒绝的回调函数
        const resolve = _Promise.reslove.bind(this)// 将实例上的静态方法的内部this绑定到实例对象
        const reject = _Promise.reject.bind(this);
        try {
            executor(resolve,reject)// 传入两个方法
        } catch (error) {// 当executor报错时把 错误值传递给解决方法
            reject(error)
        }
    }
     reslove(value){
        // 当状态为等待状态时改变promise实例状态为 成功
        if(this.status ===  _Promise.PENGIND){
            this.status = _Promise.FULFILLED
            this.value = value;
            // 异步执行then方法里的回调函数
            setTimeout(() => {
                this.onResloveCallbackS.map(callback => callback.onFulfilled(this.value))
            });
          
        }
    }
     reject(reason){
           // 当状态为等待状态时改变promise实例状态为拒绝
        if(this.status === _Promise.PENGIND){
            this.status = _Promise.REJECTED
            this.reason = reason;
             // 异步执行then方法里的回调函数, 
            setTimeout(()=>{
                //  把then里面的回调函数进行执行并传参
                this.onResloveCallbackS.map(callback => callback.onRejected(this.reason))
            })
        }
    }

    then(onFulfilled=()=>{},onRejected=()=>{}){// 给then方法内的两个回调函数添加默认值
        //  如果传递参数的类型不是函数, 就抛出一个错误
       if(typeof onRejected !== "function" ||typeof onRejected !== "function"){
           throw new Error('The argument type must be a function')
       }
       //当状态为准备时, 将then内部的函数放在状态改变时执行
       if(this.status === _Promise.PENGIND){
            this.onResloveCallbackS.push({
                onFulfilled: value => {// value 会接受promise状态改变时传递的值
                    try {// 对异步状态时进行trycatch 捕获错误
                        onFulfilled(value)// 执行成功状态时方法
                    } catch (error) {
                        onRejected(error)// 将错误抛给onRejected 方法处理
                    }
                   
                }
            })
            this.onRejectEdCallbackS.push({
                onRejected: reason =>{
                    try {
                        onRejected(reason)
                    } catch (error) {
                        onRejected(error)
                    }
                }
            })
       }
       //当Promise实例状态为成功时调用onfulfilled函数, 并传入实例对象上的value值
        if(this.status === _Promise.FULFILLED){
            // 异步执行 then方法里的回调函数
            setTimeout(() => {
                try {// 捕获then回调函数执行是发生时的错误
                    onFulfilled(this.value);
                } catch (error) {
                    onRejected(error)
                }
            });
        }
        if(this.status === _Promise.REJECTED){
            setTimeout(() => {
                try {
                    onRejected(this.reason)
                } catch (error) {
                    onRejected(error)
                }
            });
        }
    }
}
3. 链式promise

我们可以给then方法返回一个新promise,并将then返回的数据传递给新promise, 当发生错误时, 传递给reslove, 当发生异常时,我们通过trycatch 捕获并传递给 reject

class _Promise {
    static PENGIND = 'PENDING';// 准备状态常量
    static FULFILLED = 'FULFILLED';// 成功状态
    static REJECTED = 'REJECTED';//拒绝状态
    constructor(executor) {
        this.status = _Promise.PENGIND;// 定义promise 状态, 默认为 准备状态
        this.value = undefined; //     保存状态成功时传递的值
        this.reason = undefined; // 保存状态拒绝时传递的值
        this.onResloveCallbackS = [];  // 保存状态成功的回调函数
        this.onRejectEdCallbackS = []; //保存状态拒绝的回调函数
        //用于class 默认使用严格模式, 所有需要手动绑定this
        const resolve = this.reslove.bind(this)
        const reject = this.reject.bind(this);
        try {
            executor(resolve, reject)// 传入两个方法
        } catch (error) {// 当executor报错时把 错误值传递给解决方法
            reject(error)
        }
    }
     reslove(value) {
        // 当状态为等待状态时改变promise实例状态为 成功
        if (this.status === _Promise.PENGIND) {
            this.status = _Promise.FULFILLED
            this.value = value;
            // 异步执行then方法里的成功方法
            setTimeout(() => {
                this.onResloveCallbackS.map(callback => callback.onFulfilled(this.value))
            });
        }
    }
     reject(reason) {
        // 当状态为等待状态时改变promise实例状态为拒绝
        if (this.status === _Promise.PENGIND) {
            this.status = _Promise.REJECTED
            this.reason = reason;
            // 异步执行then方法里的拒绝方法, 
            setTimeout(() => {
                //  把then里面的回调函数进行执行并传参
                this.onRejectEdCallbackS.map(callback => callback.onRejected(this.reason))
            })
        }
    }
    //  默认返回 实例对象上的用于保存状态所对应的值, 实现then方法的穿透
    then(onFulfilled = () => this.value, onRejected = () => this.reason) {// 给then方法内的两个回调函数添加默认值
        //  如果传递参数的类型不是函数, 就抛出一个错误
        if (typeof onRejected !== "function" || typeof onRejected !== "function") {
            throw new Error('The argument type must be a function')
        }
        let promise =  new _Promise((reslove, reject) => {
               //当状态为准备时, 将then内部的函数放在状态改变时执行
            if (this.status === _Promise.PENGIND) {
                this.onResloveCallbackS.push({
                    onFulfilled: value => {// value 会接受promise状态改变时传递的值
                        this.parse(promise,onFulfilled(value), reslove, reject)
                    }
                })
                this.onRejectEdCallbackS.push({
                    onRejected: reason => {
                        this.parse(promise,onRejected(reason), reslove, reject);
                    }
                })
            }
            //当Promise实例状态为成功时调用onfulfilled函数, 并传入实例对象上的value值
            if (this.status === _Promise.FULFILLED) {
                // 异步执行 then方法里的回调函数
                setTimeout(() => {
                    this.parse(promise,onFulfilled(this.value), reslove, reject);
                });
            }
            if (this.status === _Promise.REJECTED) {
                this.parse(promise,onFulfilled(this.reason), reslove, reject);
            }
        })
        return promise // 返回新的promise
    }
    // 解析promise 状态
    parse(promise,result,reslove,reject){//
        if(promise === result){ // 对then 返回的值进行约束,不能返回自己的promise, 否者抛出错误
            throw new TypeError('Chaining cycle detected for promise #<Promise>')
        }
        try {// 状态执行时进行trycatch 捕获错误
            if(result instanceof _Promise){// 如果状态改变执行方法返回的是一个promise
                 result.then( res => reslove(res), reason => reject(reason)) 
                  // 因为res和rej 方法默认会执行,并传递参数, 所以我们可以简写成这种形式
                 // result.then(reslove,reject) 
            }else{
                reslove(result)// 改状态成功时返回的参数传递给下一个promise的reslove方法
            }
        } catch (error) {
            //当当一个promise发生错误时, 将错误抛给下一个promise的reject方法
            reject(error)// 将错误抛给onRejected 方法处理
        }
    }
}
4. 实现静态reslove, reject方法
  static reslove(value){
        return new _Promise((reslove,reject) =>{// 返回一个新的的promise 
            if(value instanceof _Promise){//判断传递的是否为一个promise
                value.then(reslove,reject)// 传递promise状态值
            }else{
                reslove(value)
            }
        })
    }
    static reject(reason){
        return new _Promise((reslove,reject) =>{
            reject(reason)
        })
    } 
5. 实现promise.all方法
static All(promises){
    const values = [];// 用来保存 promise状态成功时定义的值
    return new _Promise((reslove,reject) =>{
        promises.forEach(promise => {
            promise.then(
                value =>{
                    values.push(value);
                    // 如果所有promise对应的状态都为成功,即他们的数组长度相同,
                    if(values.length === promises.length){
                        reslove(values) //调用成功状态执行的回调函数 并传值
                    }
                },
                reason => {
                    reject(reason)// 调用拒绝状态执行的回调函数 并传值
                }
            )
        });
    })
 }
上一篇下一篇

猜你喜欢

热点阅读