手写简易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基础的我感觉!

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

相关推荐
子兮曰14 小时前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰14 小时前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万15 小时前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝15 小时前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋15 小时前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
晨米酱16 小时前
AGENTS.md:Agent 的上下文策略层
面试·架构·agent
卡布鲁16 小时前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
彧azz17 小时前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
汉堡大王952717 小时前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大18 小时前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端