promise梳理 + 手写

27 阅读2分钟

promise使用场景

  • promisepromise A+ 规范的实现,promise A+点这里了解

  • 最常用的是封装axios请求

function get(url, params) {
    return new Promise((resolve, reject) => {
        axios
            .get(url, {
                params: params
            })
            .then(res => {
                resolve(res)
            })
            .catch(err => {
                reject(err)
            })
    })
}

判断一个对象是否为promise

  • promise是一个对象或者函数,有一个then方法
function isObject(){
    return obj !== null && typeof obj === 'object'
}
function isFunction(){
    return obj !== null && typeof obj === 'function'
}
function isPromise(val) {
    return isObject(val) && isFunction(val.then) && isFunction(val.catch);
}

第一步,同步

class myPromise {
    #state = 'pending';
    #result = undefined;

    constructor(exe) {
        try {
            exe(this.resolve.bind(this), this.reject.bind(this))
        } catch (error) {
            this.reject(error)
        }
    }
    resolve(data) {
        if (this.#state != 'pending') return
        this.#state = 'resolved'
        this.#result = data
    }
    reject(data) {
        if (this.#state != 'pending') return
        this.#state = 'rejected'
        this.#result = data
    }
    then(onFulled, onRejected) {
        if (this.#state == 'resolved') {
            onFulled(this.#result)
        }
        if (this.#state == 'rejected') {
            onRejected(this.#result)
        }
    }
}
  • 同步测试结果,正确打印1
const p1 = new myPromise((resolve, reject) => {
    resolve('1');
}).then(res => {
    console.log(res)
})
  • 异步测试结果,无报错,无打印
const p1 = new myPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('1');
    }, 1000)
}).then(res => {
    console.log(res)
})

第二步,同步+异步

  • 异步的时候,then函数里面状态还是pending,代码需要修改修改

  • 异步的时候,收集需要执行的函数,在状态改变后执行收集的函数,(发布 - 订阅)

  • 代码修改之后,同步异步都正常了

class myPromise {
    #state = 'pending';
    #result = undefined;
    #resolveCB = [];
    #rejectCB = [];

    constructor(exe) {
        try {
            exe(this.resolve.bind(this), this.reject.bind(this))
        } catch (error) {
            this.reject(error)
        }
    }
    resolve(data) {
        if (this.#state != 'pending') return
        this.#state = 'resolved'
        this.#result = data
        this.#resolveCB.forEach(cb => cb(data))
    }
    reject(data) {
        if (this.#state != 'pending') return
        this.#state = 'rejected'
        this.#result = data
        this.#rejectCB.forEach(cb => cb(data))
    }
    then(onFulled, onRejected) {
        // 同步
        if (this.#state == 'resolved') {
            onFulled(this.#result)
        }
        if (this.#state == 'rejected') {
            onRejected(this.#result)
        }
        // 异步
        if (this.#state == 'pending') {
            this.#resolveCB.push(onFulled)
            this.#rejectCB.push(onRejected)
        }
    }

}

第三步 同步+异步+链式调用

  • 链式调用有两个地方需要注意

  • 一个是返回一个promise

  • 另一个是值的透传,下一个then的入参是上一个then的返回结果

  • then函数异步那里,push的是一个函数,这一点很重要,理解了这一点链式调用就明白了

class myPromise {
    #state = 'pending';
    #result = undefined;
    #resolveCB = [];
    #rejectCB = [];

    constructor(exe) {
        try {
            exe(this.resolve.bind(this), this.reject.bind(this))
        } catch (error) {
            this.reject(error)
        }
    }
    resolve(data) {
        if (this.#state != 'pending') return
        this.#state = 'resolved'
        this.#result = data
        this.#resolveCB.forEach(cb => cb(data))
    }
    reject(data) {
        if (this.#state != 'pending') return
        this.#state = 'rejected'
        this.#result = data
        this.#rejectCB.forEach(cb => cb(data))
    }
    then(onFulled, onRejected) {
        return new myPromise((resolve, reject) => {
            // 同步
            if (this.#state == 'resolved') {
                const res = onFulled(this.#result)
                this.resolveMyPromise(res, resolve, reject)
            }
            if (this.#state == 'rejected') {
                const err = onRejected(this.#result)
                this.resolveMyPromise(err, resolve, reject)
            }

            // 异步
            if (this.#state == 'pending') {
                this.#resolveCB.push(() => {
                    const res = onFulled(this.#result)
                    this.resolveMyPromise(res, resolve, reject)
                    resolve(res)
                })
                this.#rejectCB.push(() => {
                    const err = onRejected(this.#result)
                    this.resolveMyPromise(err, resolve, reject)
                })
            }
        })
    }
    resolveMyPromise(res, resolve, reject) {
        if (res instanceof myPromise) {
            res.then((val) => resolve(val), (err) => reject(err))
        } else {
            resolve(res)
        }
    }
}

第四步 同步+异步+链式调用+all+race

  • all是等到所有都完成或有一个失败,就返回新的promise

  • race是有一个完成就返回新的promise

    all(arr) {
        return new myPromise((resolve, reject) => {
            const result = []
            for (let i = 0; i < arr.length; i++) {
                arr[i].then(val => {
                    result.push(val)
                    if (arr.length == result.length) resolve(result)
                }, reject)
            }
        })

    }
    race(arr) {
        return new myPromise((resolve, reject) => {
            for (let i = 0; i < arr.length; i++) {
                arr[i].then(resolve, reject)
            }
        })
    }

总结

  • promise手写到这一步,大部分面试官都解决了

  • then函数是在微任务里面执行的,本文没有如此深入