【JavaScript进阶】手写ES6的Promise

// 实现ES6的promise功能

// states
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

// 用ES6的类定义一个构造函数
class myPromise {
    // 私有属性#
    #state = PENDING
    #result = undefined
    #handler = undefined // 记录then方法传入的方法

    constructor(executor) {
        const resolve = (data) => {
            this.#changeState(FULFILLED, data)
        }
        const reject = (reason) => {
            this.#changeState(REJECTED, reason)
        }
        try {
            // 只能捕获同步错误,异步报错无法捕获,状态会一直停留在'pending'
            executor(resolve, reject)
        }
        catch (err) {
            reject(err)
        }
    }

    #changeState(state, result) {
        if (this.#state !== PENDING) return
        this.#state = state
        this.#result = result
        this.#run
    }

    // 判断是否符合promise A+规范:一个对象或函数,且具有then方法就符合
    #isPromiseLike(value) {
        if (value !== null && (typeof value === 'object' || typeof value === 'function')) {
            return typeof value.then === 'function'
        }
        return false
    }

    // 在微队列中执行回调函数
    #runMicroTask(func) {
        // node环境中
        if (typeof process === 'object' && typeof process.nextTick === 'function') {
            process.nextTick(func)
        }
        // 浏览器环境,使用MutationObserver观察一个文本节点,当其变化,就会把函数放入微队列中执行
        else if (typeof MutationObserver === 'function') {
            const ob = new MutationObserver(func)
            const textNode = document.createTextNode('1')
            ob.observe(textNode, {
                characterData: true
            })
            textNode.data = '2'
        }
        // 如果当前浏览器环境不支持MutationObserver,降级为setTimeout
        else {
            setTimeout(func, 0)
        }
    }

    #runOne(callback, resolve, reject) {
        this.#runMicroTask(_ => {
            if (typeof callback !== 'function') { // 传入的回调函数不为函数,则根据当前的promise状态返回
                const settled = this.#state === FULFILLED ? resolve : reject
                settled(this.#result)
                return
            }
            try {
                const data = callback(this.#result)
                if (this.#isPromiseLike(data)) { // 传入的回调函数为函数,执行后的返回值为promise,则继续链式调用then方法
                    data.then(resolve, reject)
                } else {
                    resolve(data) // 执行后不为promise,则直接返回
                }
            } catch (err) {
                reject(err)
            }
        })
    }

    #run() {
        if (this.#state !== PENDING) return
        while (this.#handler.length) {
            const { onFulfilled, onRejected, resolve, reject } = this.#handler.shift()
            if (this.#state === FULFILLED) {
                this.#runOne(onFulfilled, resolve, reject)
            } else if (this.#state === REJECTED) {
                this.#runOne(onRejected, resolve, reject)
            } else {

            }
        }

    }

    then(onFulfilled, onRejected) {
        return new myPromise((resolve, reject) => {
            // then方法可以会执行多次,把每次的回调函数等用数组储存起来
            this.#handler.push({
                onFulfilled,
                onRejected,
                resolve,
                reject
            })
            this.#run()
        })
    }

    // catch方法返回失败回调
    catch(onRejected) {
        return this.then(undefined, onRejected)
    }

    // finally方法,对于当前promise进行不判断状态的回调
    finally(onFinally) {
        return this.then(data => {
            onFinally()
            return data // finally状态透明,成功和失败都返回promise的状态
        }, err => {
            onFinally()
            throw err
        })
    }

    // resolve方法返回一个promise,如果传入的值为promise实例,即返回传入值
    static resolve(value) {
        if (value instanceof myPromise) return value
        let _resolve, _reject
        const p = new myPromise((resolve, reject) => {
            _resolve = resolve
            _reject = reject
        })
        if (p.#isPromiseLike(value)) {
            value.then(_resolve, _reject)
        } else {
            _resolve(value)
        }
        return p
    }

    // reject方法返回一个失败的promise,并把传入值作为失败原因抛出
    static reject(reason) {
        return new myPromise((resolve, reject) => {
            reject(reason)
        })
    }
}

// 测试一下:
const mp1 = new myPromise((resolve, reject) => {
    setTimeout(_=>{
        resolve(1)
    }, 1000)
})

const mp2 = new myPromise((resolve, reject) => {
    setTimeout(_=>{
        reject(2)
    }, 1000)
})

console.log(mp1) // myPromise {#state: 'fulfilled', #result: 1, #handler: undefined}
console.log(mp2) // myPromise {#state: 'rejected', #result: 2, #handler: undefined}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值