【手写】Promise

本文根据尚硅谷的Promise讲解视频,详细介绍了如何手写Promise,从最初的es5函数构造函数版,利用setTimeout模拟异步,再到尝试使用queueMicrotask改进以更准确地模拟微任务,探讨了模拟过程中的问题和与原生Promise的差异。通过实例和链接,读者可以深入理解Promise的工作原理。
摘要由CSDN通过智能技术生成

根据尚硅谷promise讲解视频写的 链接

es5 function构造函数版,使用setTimeout模拟异步,但实际上promise应该是微任务

/*  疑难点
    1.为什么要进行保存this
        首先理清整个运行的逻辑,首先let p = new Promise(excutor)这个时候,
        会自动执行Promise函数里面的内容,当走到this.PromiseState = 'pending',没有问题,this是实例对象p
        但是当走到excutor(resolve,reject)的时候,会运行该函数
        那么这个函数,又是外部指定的箭头函数,然后运行相对应的resolve()或者reject()
        运行这个函数是window在调用,在函数内部的this就自然的变成了window,而不再是实例对象p

    2.用queueMicrotask替换setTimeout,改成微任务

*/

// 声明构造函数
function Promise(excutor) {
   
    // 添加属性,属于实例对象
    this.PromiseState = 'pending'
    this.PromiseResult = null

    // 声明回调函数的属性,用数组,保存链式调用的多个回调
    this.callbacks = []

    // 保存实例对象的this值
    const self = this

    // 声明参数 resolve/reject
    function resolve(data) {
   
        // 此处的this为window
        // console.log(this);

        // 判断PromiseState是否改变过
        if (self.PromiseState !== 'pending') return

        // 1.修改对象状态(PromiseState),属于实例对象的
        self.PromiseState = 'resolved'
        // 2.设置对象结果值(PromiseResult)
        self.PromiseResult = data


        // 判断是否有保存好了的回调函数,forEach不会对空数组进行操作,所以省去了判断
        //异步执行
        setTimeout(() => {
   

            self.callbacks.forEach(item => {
   
                item.onResolved(data)
            })
        });
    }
    function reject(data) {
   
        if (self.PromiseState !== 'pending') return
        self.PromiseState = 'rejected'
        self.PromiseResult = data

        setTimeout(() => {
   

            self.callbacks.forEach(item => {
   
                item.onRejected(data)
            })
        });
    }

    //处理错误的时候,返回一个失败的promise对象
    try {
   

        // 同步调用 执行器函数
        excutor(resolve, reject)
    } catch (error) {
   
        // 修改promise对象状态为失败
        reject(error)
    }
}

// 添加then 方法 , 实际上之所以说promise是异步的,指的是then方法里面执行onResolved是异步执行的
// promise创建的时候excutor等都是同步的,连then方法中也不全都是异步的,只有执行excutor中的参数resolve或者reject的时候才是异步
// 此处用setTimeout来模拟异步,但是官方的promise 是微任务,setTimeout是宏任务,网上好像是用的queueMicrotask()
Promise.prototype.then = function (onResolved, onRejected) {
   
    const self = this

    // 给onRejected指定一个函数,以防then只写一个参数,为了异常穿透
    if (typeof onRejected !== 'function') {
   
        onRejected = reason => {
   
            throw reason
        }
    }
    // 给onResolved指定一个函数,以防then不写参数,没传就返回的是undefined
    if (typeof onResolved !== 'function') {
   
        onResolved = value => value
    }

    return new Promise((resolve, reject) => {
   
        // 封装反复使用的函数
        function callback(type) {
   
            try {
   
                // 获取回调函数的执行结果
                let result = type(self.PromiseResult)
                if (result instanceof Promise) {
   
                    // 返回一个成功或者失败的Promise对象
                    result.then(v => {
   //v是then回调内部return的结果
                        resolve(v)
                    }, r => {
   
                        reject(r)
                    })
                } else {
   
                    // 返回一个成功的Promise对象
                    resolve(result)
                }
            } catch (error) {
   
                reject(error)
            }
        }

        // 调用回调函数 根据PromiseState
        if (this.PromiseState === 'resolved') {
   //then方法是由实例对象p调用的,所以可以根据this来得到PromiseState
            // 模拟异步,但实际上应该用微任务,这里暂时不知道怎么加入微任务队列,好像是queueMicrotask()
            setTimeout(() => {
   

                callback(onResolved)
            });
        }
        if (this.PromiseState === 'rejected') {
   
            setTimeout(() => {
   

                callback(onRejected)
            });
        }

        // 判断pending状态,比如异步的时候,要在这里等待异步结果,要不然无法处理异步任务
        // 另一个处理方式是,保存回调函数,让异步函数处理出结果的时候,判断有没有保存好的回调,如果有,那么就执行,如果没有那么说明异步,可以顺利通过then方法解决
        if (this.PromiseState === 'pending') {
   
            // 保存回调函数,用数组,保存链式调用的多个回调
            this.callbacks.push({
   
                onResolved: function () {
   
                    callback(onResolved)
                },
                onRejected: function () {
   
                  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值