js手写简易版本的Promise

本文深入探讨了Promise的原理,详细介绍了如何手动实现一个基本的Promise构造函数,包括resolve和reject的处理,以及then方法的注册和执行。通过实例展示了Promise的状态变迁,并分析了同步与异步调用resolve时的情况,最后补充了状态管理和微任务的使用,以确保正确执行回调函数。
摘要由CSDN通过智能技术生成

原生Promise的基本用法

const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('我是resolve的值')
    }, 200)
})

p.then((value) => {
    console.log(`成功时时触发我:${value}`)
}, (error) => {
    console.log(`失败时触发我:${error}`);
})

Promise是一个构造函数,使用new操作符来实例化,生成的p具有then方法,用来注册成功时回调(onFulfilled)或者失败时回调(onRejected

动手实现

Promise传入了一个函数fn,并且在实例化的时候执行了这个fn,顺便传递了resolvereject函数

function Promise(fn) {
    // 用来执行成功的回调
    const resolve = (value) => {
        
    }
    // 用来执行失败的回调
    const reject = (error) => {
        
    }
    // 实例化直接执行初始函数
    fn(resolve, reject)
}

Promise实例化以后具有一个then方法,说明then方法在原型上边,then方法用来注册成功时回调(onFulfilled)或者失败时回调(onRejected

Promise.prototype.then = function (onFulfilled, onRejected) {
    this.onFulfilled = onFulfilled
    this.onRejected = onRejected
}

一旦onFulfilled和onRejected被注册成功之后,我们就可以在resolvereject 当中执行这两个回调

function Promise(fn) {
    this.value = null
    this.error = null
    this.onFulfilled = null
    this.onRejected = null
    // 用来执行成功的回调
    const resolve = (value) => {
        this.value = value
        this.onFulfilled(value)
    }
    // 用来执行失败的回调
    const reject = (error) => {
        this.error = error
        this.onRejected(error)
    }
    // 实例化直接执行初始函数
    fn(resolve, reject)
}

开始测试

const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('我是resolve的值')
    }, 200)
})

p.then((value) => {
    console.log(`成功时时触发我:${value}`)
}, (error) => {
    console.log(`失败时触发我:${error}`);
})

分析执行流程

  • 先实例化得到一个p,此时p身上的valueerroronFulfilledonRejected 都还只是null
  • 这时候调用p.then()方法,传入了两个函数用于注册onFulfilled和onRejected,
  • then执行完毕以后,p身上的onFulfilled 、onRejected 就变成了函数
  • 过了200毫秒,执行了resolve(),在resolve里边调用了p身上的onFulfilled
  • 于是控制台输出 “成功时时触发我:我是resolve的值”

问题分析

new Promise的时候,resolve是在200毫秒以后调用的,如果是立即调用resolve会发生什么?

const p = new Promise((resolve, reject) => {
    resolve('我是resolve的值')
})
p.then((value) => {
    console.log(`成功时时触发我:${value}`)
}, (error) => {
    console.log(`失败时触发我:${error}`);
})

我们发现,当resolve调用的时候,其实then还没开始执行,于是p身上的onFulfilled还只是null,此时去强行执行resolve,并触发onFulfilled回调就会报错,那应该如何处理?
我们要想一个办法,保证resolve执行的时候,onFulfilled已经注册成为函数,于是可以这样

function Promise(fn) {
    this.value = null
    this.error = null
    this.onFulfilled = null
    this.onRejected = null
    // 用来执行成功的回调
    const resolve = (value) => {
        setTimeout(() => {
            this.value = value
            this.onFulfilled(value)// 兼容同步任务,而把回调执行的时机推迟到宏任务当中
        })
    }
    // 用来执行失败的回调
    const reject = (error) => {
        setTimeout(() => {
            this.error = error
            this.onRejected(error)
        })
    }
    // 实例化直接执行初始函数
    fn(resolve, reject)
}

既然resolve 执行的时候onFulfilled还是null,那就干脆把onFulfilled执行的时间往后推迟,推迟到宏任务队列当中去,这样就保证了,then方法先执行,onFulfilled函数后执行
可是原生Promise当中,onFulfilled不是在宏任务当中,而是放在了微任务里面,为的是更快地执行onFulfilled,于是修改代码,把setTimeout改成queueMicrotask

function Promise(fn) {
    this.value = null
    this.error = null
    this.onFulfilled = null
    this.onRejected = null
    // 用来执行成功的回调
    const resolve = (value) => {
        queueMicrotask(() => {
            this.value = value
            this.onFulfilled(value)// 兼容同步任务,而把回调执行的时机推迟到宏任务当中
        })
    }
    // 用来执行失败的回调
    const reject = (error) => {
        queueMicrotask(() => {
            this.error = error
            this.onRejected(error)
        })
    }
    // 实例化直接执行初始函数
    fn(resolve, reject)
}

到这里,Promise的基本功能就出来了

进一步完善

Promise还有3种状态:‘pending’、‘fulfilled’、‘rejected
代码中补充3种状态

function Promise(fn) {
    this.value = null
    this.error = null
    this.onFulfilled = null
    this.onRejected = null
    this.status = 'pending'
    // 用来执行成功的回调
    const resolve = (value) => {
        if (this.status === 'pending') {
            queueMicrotask(() => {
                this.status = 'fulfilled'
                this.value = value
                this.onFulfilled(value)// 兼容同步任务,而把回调执行的时机推迟到微任务当中
            })
        }
    }
    // 用来执行失败的回调
    const reject = (error) => {
        if (this.status === 'pending') {
            queueMicrotask(() => {
                this.status = 'rejected'
                this.error = error
                this.onRejected(error)
            })
        }
    }
    // 实例化直接执行初始函数
    fn(resolve, reject)
}

// 用于注册onFulfilled和onRejected
Promise.prototype.then = function (onFulfilled, onRejected) {
    if (this.status === 'pending') {
        this.onFulfilled = onFulfilled
        this.onRejected = onRejected
    } else if (this.status === 'fulfilled') {
        onFulfilled(this.value)
    } else {
        onRejected(this.error)
    }
}

观察代码发现,Promise的状态只会从‘pending’变为‘fulfilled’,或者从‘pending’变为‘rejected’,一旦状态改变了,就不会再发生变化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值