原生实现promise

一、准备工作

要实现promise,先看看promise是什么、做了哪些。
Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值,有以下两个特点:
    1、对象的状态不受外界影响。
         Promise 对象代表一个异步操作,有三种状态:
         pending: 初始状态,不是成功或失败状态。
         fulfilled: 意味着操作成功完成。
         rejected: 意味着操作失败。
    2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。

一个promise基本的代码功能大致如下,需要接收函数运行处理,提供resolve、reject方法并返回操作成功/失败的结果。

new Promise((resolve, reject) => {
    setTimeout(()=>{
        resolve(222);
    },2000)
}).then(res => {
    console.log('res',res);
});

需要哪些必要元素实现这些功能?

接收运行函数,

提供resolve、reject方法保存成功、失败的结果

then方法抛出res、err信息

res、err存储变量

保存成功、失败的变量,以此为判断依据抛出res、err

二、代码实现

1、先写下大致框架


const PENDDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MyPromise {
    constructor(callback) {
        this.status = PENDDING
        this.succ_data = undefined
        this.err_data = undefined
        callback(resolve,reject)
    }
    resolve(val) {
    }
    reject(err) {
    }
    then(onFulFilled, onRejected) {
    }
}

2、完善、验证一下

1>. 回调函数为匿名函数时,回调函数的this会指向window,需要对回调函数bind(this)。
2>. 回调函数为箭头函数时,回调函数的this会指向他的直接上层,本例中指向obj,objx。

const PENDDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MyPromise {
    constructor(callBack) {
        this.status = PENDDING
        this.succ_data = undefined
        this.err_data = undefined
        this.then = this.then.bind(this) //绑定下this指向, 类比较特殊
        this.resolve = this.resolve.bind(this)
        this.reject = this.reject.bind(this)
        try{
            callBack(this.resolve, this.reject)
        }catch(err){
            this.reject(err)
        }
    }
    resolve(val) {
        if (this.status !== PENDDING) { //状态只能从PENDDING而来
            return false 
        }
        this.succ_data = val //存储成功数据
        this.status = FULFILLED // 改变状态,处理ok
    }
    reject(err) {
        if (this.status !== PENDDING) { //状态只能从PENDDING而来
            return false 
        }
        this.err_data = err //存储失败数据
        this.status = REJECTED // 改变状态,处理ok
    }
    then(onFulFilled, onRejected ){
        if(this.status === FULFILLED){
            onFulFilled(this.succ_data)
        }
        if(this.status === REJECTED){
            onRejected(this.err_data)
        }
    }    
}

会发现并未如期望的打印出res,这是因为then方法时,resolve还未执行,此时的succ_data还是undefined

解决:暂存then任务至数组,当status改变时继续执行

3、添加队列相关代码

    then(onFulFilled, onRejected ){
        if(this.status === FULFILLED){
            onFulFilled(this.succ_data)
        }else if(this.status === REJECTED){
            onRejected(this.err_data)
        }else{
            this.queue.push({resolve:onFulFilled,reject:onRejected}) //实际是将then的功能在resolve阶段完成
        }
    }   
    resolve(val) {
        if (this.status !== PENDDING) { //状态只能从PENDDING而来
            return false 
        }
        this.succ_data = val //存储成功数据
        this.status = FULFILLED // 改变状态,处理ok
        if( this.queue.length > 0 ){
            this.queue.map((item,index)=>{
                item.resolve(val)
            })
        }
    }
    reject(err) {
        if (this.status !== PENDDING) { //状态只能从PENDDING而来
            return false 
        }
        this.err_data = err //存储失败数据
        this.status = REJECTED // 改变状态,处理ok
        if( this.queue.length > 0 ){
            this.queue.map((item,index)=>{
                item.resolve(err)
            })
        }
    }

4、链式调用

原生的 Promise 对象的then方法,返回的也是一个 Promise 对象,一个新的 Promise 对象,这样才可以支持链式调用,一直then下去。。。 而且,then方法可以接收到上一个then方法处理return的结果。根据Promise的特性分析,这个返回结果有3种可能:

  1. MyPromise对象;
  2. 具有then方法的对象;
  3. 其他值。 根据这三种情况分别处理。
  • 第一个处理的是,then方法返回一个MyPromise对象,它的回调函数接收resFnrejFn 两个回调函数;
  • 把成功状态的处理代码封装为handleFulfilled函数,接受成功的结果作为参数;
  • handleFulfilled函数中,根据onFulfilled返回值的不同,做不同的处理:
    • 首先,先获取onFulfilled的返回值(如果有),保存为returnVal
    • 然后,判断returnVal是否有then方法,即包括上面讨论的1、2中情况(它是MyPromise对象,或者具有then方法的其他对象),对我们来说都是一样的;
    • 之后,如果有then方法,马上调用其then方法,分别把成功、失败的结果丢给新MyPromise对象的回调函数;没有则结果传给resFn回调函数。
    then(onFullFiled, onRejected){
        const _this = this
        return new MyPromise((resFn,rejFn)=>{
            switch(this.status){
                case PEDDING:
                    this.queue.push({
                        resolve:onFullFIled,
                        handleRej:onRejected
                    })
                    break;
                case RESOLVED:
                    console.log('this.success_data', this.success_data)
                    handleRes(this.success_data)
                    break;
                case REJECTED:
                    handleRej(this.error_data)
                    break;
            }
            function handleRes(val){
                let returnVal = onFullFiled instanceof Function && onFullFiled(val) || val   //获取码农返回的promise
                console.log('returnVal',returnVal)

                if(returnVal['then'] && returnVal['then'] instanceof Function){
                    returnVal.then(res=>{  //获取码农希望的resolve/reject的值,并resolve/reject
                        resFn(res)
                        // console.log('resFn(res)',res)

                    },err=>{
                        rejFn(err)
                    })
                }else{
                    resFn(val)
                }
            }
            function handleRej(val){
                let returnVal = onRejected instanceof Function && onRejected(val) || val //获取码农返回的promise
                if(returnVal['then'] && returnVal['then'] instanceof Function){
                    returnVal.then(res=>{ //获取码农希望的resolve/reject的值,并resolve/reject
                        resFn(res)
                    },err=>{
                        rejFn(err)
                    })
                }else{
                    rejFn(val)
                }
            }
        })
    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值