手写简易promise!实现promise链式调用

今天带大家实现手写promise啊!加油加油


简介

promise作为处理异步的常见方法,它可以使异步代码看起来像同步一样执行。它用来解决地狱回调问题,使得代码可读性大大增加。

一个 Promise 必然处于以下几种状态之一:

待定(pending):初始状态,既没有被兑现,也没有被拒绝。

已兑现(fulfilled):意味着操作成功完成。

已拒绝(rejected):意味着操作失败。

难点

对于实现手写promise主要有这么几个难点

  1. 代码的执行顺序问题
  2. 代码的this指向问题
  3. 链式调用会出现的递归问题

实现代码

简单promise

首先我们凭直觉应该能写出这样的代码,即promise是一个class,在new promise的过程中其实是在创建这个class的实例。

而这个class中至少应该有这么几个方法:

  1. constructor :用于接收这个回调函数并执行
  2. resolve :用于处理状态转变为fulfilled后所需要做的事情
  3. reject :用于处理状态转变为rejected后所需要做的事情
  4. then :用于接收状态改变为fulfilled/rejected后的回调函数

需要注意的点在于这段代码,这么写是因为constructor内执行的是个异步函数,它的执行顺序并不确定,如果他是setTimeout(()=>{},0)那么它就比then快,如果不是0秒他就会比then慢,所以这里要分情况讨论

kotlin 复制代码
 then(f1:IResolve,f2?:IReject){
        if(this.status=="fulfilled"){
            console.log("运行了成功")
            f1(this.data)

        }else if(this.status=="rejected"){
            f2(this.data)
        }else if(this.status=="padding"){
            this.f1f2.push([f1,f2])
        }
    }

然后还有一些小的this指向问题,this丢了再用call/bind绑定一下就行了!

然后我们凭借程序员的直觉就能写出下面的代码了!。(❁´◡`❁)

kotlin 复制代码
type IFn=(resolve:IResolve,reject:IReject)=>void
type IResolve<T=any>=(data:T)=>void
type IReject<T=any>=(data:T)=>void
class Promise2{
    private status='pending'
    private f1f2:[IResolve,IReject][]=[]
    private data:any
    constructor(fn:IFn) {
        fn.call(this,this.resolve.bind(this),this.reject.bind(this));
    }
    resolve(data):IResolve{
        console.log("运行resolve")
        this.status="fulfilled"
        this.data=data;
        let arriveF1f2=this.f1f2.shift();
        if(arriveF1f2){
            arriveF1f2[0](data);
        }
        return

    }

    reject(data):IReject{
        this.status="rejected"
        this.data=data;
        let arriveF1f2=this.f1f2.shift();
        if(arriveF1f2[1]){
            arriveF1f2[1](data);
        }
        return
    }

    then(f1:IResolve,f2?:IReject){
        if(this.status=="fulfilled"){
            console.log("运行了成功")
            f1(this.data)

        }else if(this.status=="rejected"){
            f2(this.data)
        }else if(this.status=="padding"){
            this.f1f2.push([f1,f2])
        }
    }
}
let test=new Promise2((resolve, reject)=>{
    setTimeout(()=>{
        reject("成功");
    })
})
test.then((data)=>{
    console.log("运行了回调1")
    console.log(data);
},(data)=>{
    console.log("运行了失败回调1");
})

链式调用promise

众所周知promise是可以实现链式调用的,即在.then之后继续.then。

那我们如果要实现这个功能其实也很简单,就是通过then函数返回一个新的promise来实现,然后通过执行resolve/reject函数来实现运行成功回调还是失败回调,具体是下面这几行代码

kotlin 复制代码
    then(f1:IResolve,f2?:IReject){
            return new Promise2((resolve, reject)=>{
                console.log("运行了then",this.status);
                if(this.status=="fulfilled"){
                    console.log("运行了成功")
                    this.parse(f1(this.data),resolve,reject)

                }else if(this.status=="rejected"){
                    this.parse(f2(this.data),resolve,reject)


                }else if(this.status=="pending"){
                    this.f1f2.push({
                        f1:()=>{this.parse(f1(this.data),resolve,reject)},
                        f2:()=>(this.parse(f2(this.data),resolve,reject))
                    })
                }
            })//为了实现链式调用,所以返回promise
    }

    //冗余代码
    parse(result,resolve,reject){
        try {
            if(result instanceof Promise2){
                result.then(resolve,reject)
            }else{
                resolve(result);
            }
        }catch (e){
            reject(result)
        }
    }

完整代码如下

kotlin 复制代码
type IFn=(resolve:IResolve,reject:IReject)=>void
type IResolve<T=any>=(data:T)=>any
type IReject<T=any>=(data:T)=>any
class Promise2{
    private status='pending'
    private f1f2:any[]=[]
    private data:any
    constructor(fn:IFn) {
        fn.call(this,this.resolve.bind(this),this.reject.bind(this));
    }
    resolve(data):IResolve{
        // console.log(this);
        console.log("运行resolve")
        this.status="fulfilled"
        this.data=data;
        let arriveF1f2=this.f1f2.shift();
        if(arriveF1f2?.f1){
            arriveF1f2.f1();
        }
        return

    }

    reject(data):IReject{
        this.status="rejected"
        this.data=data;
        let arriveF1f2=this.f1f2.shift();
        if(arriveF1f2.f2){
            arriveF1f2.f2();
        }
        return
    }

    then(f1:IResolve,f2?:IReject){
            return new Promise2((resolve, reject)=>{
                console.log("运行了then",this.status);
                if(this.status=="fulfilled"){
                    console.log("运行了成功")
                    this.parse(f1(this.data),resolve,reject)

                }else if(this.status=="rejected"){
                    this.parse(f2(this.data),resolve,reject)


                }else if(this.status=="pending"){
                    this.f1f2.push({
                        f1:()=>{this.parse(f1(this.data),resolve,reject)},
                        f2:()=>(this.parse(f2(this.data),resolve,reject))
                    })
                }
            })//为了实现链式调用,所以返回promise
    }

    //冗余代码
    parse(result,resolve,reject){
        try {
            if(result instanceof Promise2){
                result.then(resolve,reject)
            }else{
                resolve(result);
            }
        }catch (e){
            reject(result)
        }
    }
}
let test=new Promise2((resolve, reject)=>{
    setTimeout(()=>{
        resolve("成功");
    })
})
test.then((data)=>{
    console.log("运行了回调1")
    console.log(data);
},(data)=>{
    console.log("运行了失败回调1");
}).then((data)=>{
    console.log("运行了回调2")
    console.log(data);
},(data)=>{
    console.log("运行了失败回调2");
})

这大概就是实现promise的完整过程啦!写完这个过程还是很考验js基础的我感觉!

好啦我是发面糕!我们下回再见!(●'◡'●)

相关推荐
小桥风满袖3 小时前
极简三分钟ES6 - ES8中字符串扩展
前端·javascript
张拭心3 小时前
这就是流量的力量吗?用豆包 AI 编程做的xhs小组件帖子爆了
前端·ai编程·豆包marscode
少年阿闯~~3 小时前
CSS3的新特性
前端·javascript·css3
IT_陈寒3 小时前
React性能优化:这5个Hook技巧让我的组件渲染效率提升50%(附代码对比)
前端·人工智能·后端
青鱼入云4 小时前
【面试场景题】支付&金融系统与普通业务系统的一些技术和架构上的区别
面试·金融·架构
智能化咨询4 小时前
【Linux】【实战向】Linux 进程替换避坑指南:从理解 bash 阻塞等待,到亲手实现能执行 ls/cd 的 Shell
前端·chrome
Anson Jiang4 小时前
浏览器标签页管理:使用chrome.tabs API实现新建、切换、抓取内容——Chrome插件开发从入门到精通系列教程06
开发语言·前端·javascript·chrome·ecmascript·chrome devtools·chrome插件
掘金安东尼4 小时前
黑客劫持:周下载量超20+亿的NPM包被攻击
前端·javascript·面试
剑亦未配妥5 小时前
移动端触摸事件与鼠标事件的触发机制详解
前端·javascript