Promise ? 我 promise 你一个详细的手撕过程

手撕一个Promise详细过程

面试官问你Promise原理,以及让你手写一个Promise并实现其中的then()catch()等方法,不用呆在原地了😛,下面是我手撕Promise的过程以及一些心得,在手撕Promise之前你得知道什么是Promise以及Promise如何使用,如果有不是很熟悉的可以去看我之前写的面试系列二中的Promise前端面试题目系列二💨

其实Promsie的手写过程不是很难,大家自己动手理清思路和重要,下面是我手写Promise的源码,就实现了一些常用Promise的方法,所有的测试都能跑通,XDM放心食用,更详细的讲解放在最后了!!!

	  // 抽取封装函数
	function resolvePromise(promiseExmpl, x, resolve, reject) {
       if(x === promiseExmpl) {
           throw new TypeError('Chaining cycle detected for promise #<Promise>')
       }
           x instanceof NewPromise ? x.then(res => resolve(res), error => reject(error)) : resolve(x)        
       }

        //定义一个枚举对象来表示 Promise 的三种状态
       const Status = {
           PENDING: 'pending',
           FULFILLED: 'fulfilled',
           REJECTED: 'rejected'
       }
        // 1.0 定义类
       class NewPromise {
           status = Status.PENDING
           value = null                           //成功时的值
           reason = null                           //失败时的原因
           onFulfilledCallbacks = []              //存储成功时候的回调
           onRejectedCallbacks = []    			//存储失败时候的回调   

           constructor(fn) {

               const resolve = (value) => {
                   if(this.status === Status.PENDING) {
                       this.status = Status.FULFILLED
                       this.value = value
                       this.onFulfilledCallbacks.forEach(fn => fn(this.value))
                   }
               }
               
               const reject = (reason) => {
                   if (this.status === Status.PENDING) {
                       this.status = Status.REJECTED
                       this.reason = reason
                       this.onRejectedCallbacks.forEach(fn => fn(this.reason))
                   }
               }

               try {
                   fn(resolve, reject)
               } catch (error) {
                   reject(error)
               }
            }

            then(onFulfilled, onRejected) {
                onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
                onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error; }
                
                const promiseExmpl = new NewPromise((resolve, reject) => {
                  if(this.status === Status.FULFILLED) {
                    setTimeout(() => {
                        try {
                            let x  = onFulfilled(this.value)
                            resolvePromise(promiseExmpl, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    },0)
                }
                    
                if(this.status === Status.REJECTED) {
                    setTimeout(() => {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(promiseExmpl, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                   },0)
                }

                if(this.status === Status.PENDING) {
                    this.onFulfilledCallbacks.push(() => {
                        try {
                            const x = onFulfilled(this.value)
                            resolvePromise(promiseExmpl, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    })
                    this.onRejectedCallbacks.push(() => {
                        try {
                            const x = onRejected(this.reason)
                            resolvePromise(promiseExmpl, x. resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    })
                }
                })
                return promiseExmpl
            }    

            catch(onRejected) {
               return  this.then(null, onRejected)
            }
        }

手写Promise过程以及测试代码

        /**
         * 核心步骤:
         * 1.构造函数
         *  1.0 定义类
         *  1.1 添加构造函数
         *  1.2 定义resolve/reject方法
         *  1.3 执行回调函数   
         * 2.状态及原因
         *  2.1 添加状态 (status)
         *  2.2 添加成功值和失败原因 (value、reason)
         *  2.3 调整resolve/reject函数
         *  2.4 状态不可逆(指状态只能从Pending到达某一状态,不能从fulfilled到达rejected,反之亦然)
         * 3.then方法实现
         *  3.1 添加实例方法
         *  3.2参数判断(MDN文档中有说明 Promise.Prototype.then())
         *      3.2.1 执行成功回调
         *      3.2.2 执行失败回调
         *  3.3 支持异步及多次调用
         *      3.3.1 定义存储成功和失败的回调的实例属性
         *      3.3.2 保存then中的回调函数
         *      3.3.3 调用成功回调
         *      3.3.4 调用失败回调
         * 4.异步任务
         *  4.1 使用 setTimeout 来实现 Promise 可以确保 resolve 和 reject 的调用是在宏任务队列中执行的
         * 5.链式调用
         *  5.1 返回新的Promise实例
         *  5.2 获取返回值
         *      5.2.1 处理返回值
         *      5.2.2 处理异常
         *      5.2.3 处理返回的Promise(调用then方法)
         *      5.2.4 处理重复引用
         * 6.catch方法实现
         *  6.1 内部调用then方法
         *  6.2 异常处理
        */

        // 抽取封装函数
        function resolvePromise(promiseExmpl, x, resolve, reject) {
        //5.2.4 处理重复引用
        if(x === promiseExmpl) {
            throw new TypeError('Chaining cycle detected for promise #<Promise>')
        }
            // 5.2.1 处理返回值
            // 5.2.3 处理返回的Promise(调用then方法)
            x instanceof NewPromise ? x.then(res => resolve(res), error => reject(error)) : resolve(x)        
        }

        //定义一个枚举对象来表示 Promise 的三种状态
        const Status = {
            PENDING: 'pending',
            FULFILLED: 'fulfilled',
            REJECTED: 'rejected'
        }
        // 1.0 定义类
        class NewPromise {
            // 2.1 添加状态
            status = Status.PENDING
            // 2.2 添加原因
            value = null                           //成功时的值
            reason = null                           //失败时的原因

            // 3.3.1 定义存储成功和失败的回调的实例属性
            onFulfilledCallbacks = []              //存储成功时候的回调
            onRejectedCallbacks = []               //存储失败时候的回调   
            //构造函数就是newPromise的参数,即是一个回调函数,回调函数中的参数分别是resolve函数和reject函数
            // 1.1 添加构造函数
            constructor(fn) {
                // 1.2 resolve函数的实现
                const resolve = (value) => {
                    // 2.4 状态不可逆
                    if(this.status === Status.PENDING) {
                        // 2.3 调整resolve函数,改变状态 pengding  ---> fulfilled
                        this.status = Status.FULFILLED
                        this.value = value
                        // 3.3.3 调用回调任务队列中的成功回调
                        this.onFulfilledCallbacks.forEach(fn => fn(this.value))
                    }
                }
                // 1.2 reject函数的实现
                // 2.3 调整reject函数,改变状态 Pengding  ---> rejected
                const reject = (reason) => {
                    // 2.4 状态不可逆
                    if (this.status === Status.PENDING) {
                         // 2.3 调整resolve函数,改变状态 pengding  ---> fulfilled
                        this.status = Status.REJECTED
                        this.reason = reason
                        // 3.3.4 调用失败回调
                        this.onRejectedCallbacks.forEach(fn => fn(this.reason))
                    }
                }

                // 6.2 异常处理
                try {
                    // 1.3 执行回调函数
                    fn(resolve, reject)
                } catch (error) {
                    reject(error)
                }
            }
            // 3.1 添加实例方法
            then(onFulfilled, onRejected) {
                // 3.2参数判断
                onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
                onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error; }
                
                //5.1 返回新的Promise实例
                const promiseExmpl = new NewPromise((resolve, reject) => {
                    // 5.2 获取返回值,这个返回值是是一个then方法中成功的回调函数的返回值,即onFulfilled()的返回值
                    //第二个.then()方法其实是这个返回的新的Promise实例的
                    //关键点:Promise传入的回调函数会立即执行
                    // 3.2.1 执行成功回调
                if(this.status === Status.FULFILLED) {
                    // Promise实例中resolve()的值是then方法中成功回调函数的参数
                    //onFulfilled(this.value)  === 实例对象promise中then方法中成功的回调(res) => { }
                    setTimeout(() => {
                        try {
                            let x  = onFulfilled(this.value)
                            resolvePromise(promiseExmpl, x, resolve, reject)
                        } catch (error) {
                            // 5.2.2 处理异常
                            reject(error)
                        }
                    },0)
                }
                // 3.2.1 执行失败回调
                if(this.status === Status.REJECTED) {
                    setTimeout(() => {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(promiseExmpl, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                   },0)
                }

                if(this.status === Status.PENDING) {
                    // 3.3.2 保存then中的回调函数
                    this.onFulfilledCallbacks.push(() => {
                        try {
                            const x = onFulfilled(this.value)
                            resolvePromise(promiseExmpl, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    })
                    this.onRejectedCallbacks.push(() => {
                        try {
                            const x = onRejected(this.reason)
                            resolvePromise(promiseExmpl, x. resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    })
                }
                })
                return promiseExmpl
            }    
            
            // 6. 实现catch方法(用then方法实现catch方法,有疑惑的可以看我之前前端面试题目Promise)
            catch(onRejected) {
               return  this.then(null, onRejected)
            }
        }


        // --------------------测试代码-------------------
        console.log("top")
        const promise = new NewPromise((resolve, reject) => {
            // setTimeout(() => {
            //     resolve("success")
            //     // reject('error222')
            // },2000)
            // console.log('1111111');
             resolve("success")             //Pengding  ---> fulfilled
            // reject("error111")               //Pengding  ---> rejected
            //throw 'new error'
        })
        
        //支持链式编程
         promise.then(res => {
             // 这个成功回调函数的返回的值就是onFulfilled()的返回值
            console.log('成功回调then1:', res)
            //return 2
           // throw 'error eor'
          return new NewPromise((resolve, reject) => {
               resolve(3)
               // reject('error')
               // setTimeout(() => {
             //     resolve(4)
              // },2000)
           })
         }).then(res => {
            console.log("成功回调then2:", res)
        },error => {
            console.log("失败回调error2:", error)
        })

        //cath方法捕获rejectd的错误以及主动抛出的错误
        // promise.then(res => {
        //   console.log('成功的回调:', res)
        // }).catch(error => {
        //     console.log("错误捕获:", error)
        // })


        //原生Promise会有这个重复引用的问题,而新手写的Promise没有这个错误
        //TypeError: Chaining cycle detected for promise #<Promise>
        // const p2 = promise.then(res => {
        //     return p2
        // })

        // p2.then(res => {}, error => {
        //     console.log("重复引用错误:", error)
        // })

        //多次调用测试
        //     promise.then(res => {
        //     console.log('成功回调then2:', res)
        // },err => {
        //     console.log("失败回调error2:", err)
        //     })
        console.log("bottom")

我自己在写的过程中也出现了很多bug,最后都顺利解决了,下面这些图片可能会帮助你们理解上面的代码在这里插入图片描述在这里插入图片描述

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Promise是一种用于处理异步操作的JavaScript对象。它可以用来解决传统回调函数带来的回调地狱问题,使异步代码更加可读、可维护。 Promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。当异步操作执行成功时,Promise的状态从pending变为fulfilled;当异步操作执行失败时,状态从pending变为rejected。一旦状态改变,就会触发对应的回调函数。 使用Promise处理异步操作的一般步骤如下: 1. 创建一个Promise对象,通过new关键字实例化。 2. 在Promise对象的构造函数中传入一个执行器函数,该函数接受两个参数:resolve和reject。resolve函数用于将Promise状态从pending变为fulfilled,并传递异步操作的结果;reject函数用于将Promise状态从pending变为rejected,并传递错误信息。 3. 在执行器函数中编写异步操作的逻辑,当异步操作执行成功时调用resolve函数,传递操作结果;当异步操作执行失败时调用reject函数,传递错误信息。 4. 通过调用Promise对象的then方法可以注册成功回调函数,通过调用catch方法可以注册失败回调函数。这些回调函数会在异步操作执行成功或失败时被触发,并接收到相应的结果或错误信息。 下面是一个使用Promise处理异步操作的示例代码: ```javascript function fetchData() { return new Promise((resolve, reject) => { // 模拟异步操作 setTimeout(() => { const data = '异步操作的结果'; if (data) { resolve(data); // 异步操作成功,将状态改为fulfilled,并传递结果 } else { reject('异步操作失败'); // 异步操作失败,将状态改为rejected,并传递错误信息 } }, 2000); }); } fetchData() .then(result => { console.log('异步操作成功:', result); }) .catch(error => { console.error('异步操作失败:', error); }); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值