• 作者:老汪软件技巧
  • 发表时间:2024-12-13 04:03
  • 浏览量:

有的小伙伴操作的时候可能会有跟我一样的疑问,为什么onResolveCallbacks只有push操作,并没有删除相关的操作呢?根据其特性:状态一旦确定就不可更改,因此 onResolveCallbacks 和 onRejectCallbacks 的回调数组中只有 push 操作,无需删除元素。

然而,目前的实现并没有状态判断的功能,为了确保 Promise 的行为符合规范,我们需要加上状态判断来完善它。

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REFECTED = 'rejected'
class IPromise {
    constructor(excutor) {
        this.promiseState = PENDING // 三种状态:pending、fulfilled、rejected
        this.onResolveCallbacks = [] // 成功的回调
        this.onRejectCallbacks = [] // 失败的回调
        try {
            excutor(this.resolve, this.reject) // 这里只能捕获同步错误
        } catch (error) {
            this.reject(error)
        }
    }
    resolve = (value) => {
        if (this.promiseState !== PENDING) return // 只处理Promise为pending的情况
        this.promiseState = FULFILLED // 设置为成功的状态
        queueMicrotask(() => { // 需要放到微任务队列里面
            this.onResolveCallbacks.forEach(resolve => resolve(value))
        })
    }
    reject = (reason) => {
        if (this.promiseState !== PENDING) return
        this.promiseState = REFECTED // 设置为失败的状态
        queueMicrotask(() => { // 不放到微任务队列里的话,错误都捕获不到
            this.onRejectCallbacks.forEach(reject => reject(reason))
        })
    }
    then = (onFulfilled, onRejected) => {
        // 防止参数传空的情况
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }
        this.onResolveCallbacks.push(onFulfilled)
        this.onRejectCallbacks.push(onRejected)
    }
}
function requestFactory() {
    return new IPromise((res, rej) => {
        setTimeout(() => {
            res(100)
            rej(new Error('error'))
        }, 1000)
    })
}
const request = requestFactory()
request.then((res) => {
    console.log(res);
})

Promise是支持链式调用的,我们把then的返回值处理成Promise,这样不就可以继续then了么,先来几个例子方便我们处理边界和特殊情况

// 常规功能
new Promise((res) => {
    res(1)
})
.then(res => res * 2)
// 比较特殊的情况
new Promise((_, rej) => {
    rej(1)
})
.then() // Promise {: 1}
// 特殊的情况
new Promise((_, rej) => {
    rej(1)
})
.then()
.then(null, console.log) // log => 1
// Promise {: undefined}

观察这两种特殊情况不难发现,显式传入的onRejected返回新的Promise会变成fulfilled,undefined的情况则不做处理。

class IPromise {
    constructor(excutor) {
        this.promiseState = PENDING // 三种状态:pending、fulfilled、rejected
        this.onResolveCallbacks = [] // 成功的回调
        this.onRejectCallbacks = [] // 失败的回调
        this.value = undefined
        this.reason = undefined
        try {
            excutor(this.resolve, this.reject) // 这里只能捕获同步错误
        } catch (error) {
            this.reject(error)
        }
    }
    resolve = (value) => {
        if (this.promiseState !== PENDING) return // 只处理Promise为pending的情况
        this.promiseState = FULFILLED // 设置为成功的状态
        this.value = value // 保存一下结果
        queueMicrotask(() => { // 需要放到微任务队列里面
            this.onResolveCallbacks.forEach(resolve => resolve(value))
        })
    }
    reject = (reason) => {
        if (this.promiseState !== PENDING) return
        this.promiseState = REJECTED // 设置为失败的状态
        this.reason = reason // 保存一下出错的原因
        queueMicrotask(() => { // 不放到微任务队列里的话,错误都捕获不到
            this.onRejectCallbacks.forEach(reject => reject(reason))
        })
    }
    then = (onFulfilled, onRejected) => {
        // 防止参数传空的情况
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; }
        return new IPromise((resolve, reject) => {
            if (this.promiseState === FULFILLED) {
                // 如果状态立即被更改了,可以直接执行onFulfilled了
                const value = onFulfilled(this.value)
                resolve(value)
            }
            if (this.promiseState === REJECTED) {
                // 如果状态立即被更改了,可以直接执行onRejected了
                queueMicrotask(() => { 
                    if (onRejected) {
                        // 用户提供了 `onRejected`,正常执行回调
                        try {
                            const result = onRejected(this.reason);
                            resolve(result);
                        } catch (error) {

操作中发生疑问时有哪些规定__在操作中有疑问时怎么办

reject(error); } } else { // 用户未提供 `onRejected`,直接将状态传递给下一个 Promise reject(this.reason); } }); } if (this.promiseState === PENDING) { // 如果状态未被更改,说明是异步任务,推入对应的回调数组 this.onResolveCallbacks.push(() => { queueMicrotask(() => { try { const result = onFulfilled(this.value); resolve(result); } catch (error) { reject(error); } }); }); this.onRejectCallbacks.push(() => { queueMicrotask(() => { if (onRejected) { try { const result = onRejected(this.reason); resolve(result); } catch (error) { reject(error); } } else { reject(this.reason); // 直接将状态传递给下一个 Promise } }); }); } }) } }

有可能返回值是新的Promise,或者是自身,我们只需要调用then方法并传入当前生成的resolve,reject即可。代码有点冗余,提取一下冗余代码。

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class IPromise {
    constructor(excutor) {
        this.promiseState = PENDING // 三种状态:pending、fulfilled、rejected
        this.onResolveCallbacks = [] // 成功的回调
        this.onRejectCallbacks = [] // 失败的回调
        this.value = undefined
        this.reason = undefined
        try {
            excutor(this.resolve, this.reject) // 这里只能捕获同步错误
        } catch (error) {
            this.reject(error)
        }
    }
    resolve = (value) => {
        if (this.promiseState !== PENDING) return // 只处理Promise为pending的情况
        if (value === this) {
            // 避免返回自身导致死循环
            return this.reject(new TypeError("A promise cannot be resolved with itself."));
        }
        // 处理 value 为 Promise 的情况
        if (value instanceof IPromise) {
            return value.then(this.resolve, this.reject);
        }
        queueMicrotask(() => { // 需要放到微任务队列里面
            this.onResolveCallbacks.forEach(resolve => resolve(value))
        })
        this.promiseState = FULFILLED // 设置为成功的状态
        this.value = value // 保存一下结果
    }
    reject = (reason) => {
        if (this.promiseState !== PENDING) return
        this.promiseState = REJECTED // 设置为失败的状态
        this.reason = reason // 保存一下出错的原因
        queueMicrotask(() => { // 不放到微任务队列里的话,错误都捕获不到
            this.onRejectCallbacks.forEach(reject => reject(reason))
        })
    }
    then = (onFulfilled, onRejected) => {
        // 防止参数传空的情况
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; }
        const handleCallback = (callback, value, resolve, reject) => {
            queueMicrotask(() => {
                try {
                    const result = callback(value);
                    if (result === this) {
                        // 避免循环引用
                        return reject(new TypeError("Cannot return the same promise from then()"));
                    }
                    
                    if (result instanceof IPromise) {
                        // 如果返回值是 Promise,链接状态
                        result.then(resolve, reject);
                    } else {
                        resolve(result);
                    }
                } catch (error) {
                    reject(error);
                }
            });
        };
        return new IPromise((resolve, reject) => {
            if (this.promiseState === FULFILLED) {
                handleCallback(onFulfilled, this.value, resolve, reject);
            }
            if (this.promiseState === REJECTED) {
                handleCallback(onRejected, this.reason, resolve, reject);
            }
            if (this.promiseState === PENDING) {
                // 如果状态未被更改,说明是异步任务,推入对应的回调数组
                this.onResolveCallbacks.push(() => handleCallback(onFulfilled, this.value, resolve, reject));
                this.onRejectCallbacks.push(() => handleCallback(onRejected, this.reason, resolve, reject));
            }
        })
    }
}

至此,Promise已经能适用于绝大部分场景,但如果要完全符合 Promise/A+ 规范还需要进一步处理,下一章将说明如何实现Promise的静态方法。