Promise的原理和实现

我们已经很习惯用Promise了,但是它的实现原理是什么呢?下面我们来分析一下。
根据阮一峰老师的《ES6入门》中对于Promise的讲解。我们可以发现,Promise有两大特点:
image.png
根据我们使用Promise的情况,以及特点我们总结出来了以下几点:
1、Promise是一个异步操作。
2、Promise有三种状态(pending、fulfilled、rejected),初始为pending,其他两种为结果状态。
3、如果状态已经发生改变,那么再then的时候会立即返回结果。
4、Promise构造函数接受一个函数,函数有resolve、reject参数。
5、Promise通过then可以添加多个回调函数,当状态改变以后,会触发这些对应状态的回调的执行。
6、then有两个参数,一个代表成功的回调、一个失败的回调,结果状态的值会进入回调。
7、promise会catch住内部的异常情况。
通过以上总结,我们可以初步实现一个Promise的骨架。

const STATUS = Object.freeze({ // 定义三种状态
    PENDING: "pending",
    FULFILLED: "fulfilled",
    REJECTED: "rejected"
})
class MyPromise {
    _status = STATUS.PENDING; // 初始状态
    _value = undefined;  // 执行结果
    _fulfilledFun = []; // fulfilled状态对应执行的任务队列
    _rejectedFun = [] // rejected状态对应执行的任务队列
    constructor(handle) {
        if (!this._isFunction(handle)) {
            throw TypeError('arguments must be a function')
        }
        try { // promise 会catch住内部的执行异常
            handle(this._resolve.bind(this), this._reject.bind(this)) // Promise构造函数的回调有两个参数
        } catch (err) {
            this._reject(err)
        }

    }
    _isFunction(handle) {
        return typeof handle === 'function'
    }
    _run(tasks) {
        let cb;
        while (cb = tasks.shift()) {
            cb()
        }
    }
    _resolve(val) {
        if (this._status !== STATUS.PENDING) return;
        this._status = STATUS.FULFILLED;
        this._value = val;
        setTimeout(() => { /// 为了模拟异步,实现跟promise一样的异步效果,但是此处其实是宏队列,不是真正的promise微队列
            this._run(this._fulfilledFun)
        }, 0)
    }
    _reject(val) {
        if (this._status !== STATUS.PENDING) return;
        this._status = STATUS.REJECTED;
        this._value = val;
        setTimeout(() => {
            this._run(this._rejectedFun)
        }, 0)
    }
    then(resolve, reject) {
        const { _status, _value } = this;
        switch (_status) {
            // 添加多个回调到对应状态任务队列
            case STATUS.PENDING:
                this._fulfilledFun.push(resolve)
                this._rejectedFun.push(reject)
                break;
            //如果状态变化则立即返回结果
            case STATUS.FULFILLED: 
                resolve(_value)
                break;
            case STATUS.REJECTED:
                reject(_value)
                break;
        }
    }
}
var p = new MyPromise((res, rej) => {
    res(3333)
})
p.then((res) => {
    console.log(1, res)
})
console.log(1)
// 执行结果
//1
//1 3333
复制代码

以上我们实现了一个基本的Promise骨架。
image.png
如图我们可以发现,then返回的是一个Promise实例,但是我们上一步并没有任何返回,所以我们要把then改造一下,对then进行一个扩充。

class MyPromise {
  	//.....
  	//用于对then的返回值进行处理
  	_handleCheck(preTask, nextTask, nextResolve, nextReject) {
        let result = this._value;
        try {
            if (this._isFunction(preTask)) {
                result = preTask(result)
                if (result instanceof MyPromise) { // 如果then返回的是一个promise的话,那么下一个链式调用使用的是then中promise的返回值
                    result.then(nextResolve, nextReject)
                } else {
                    nextTask(result)
                }
            } else { // 这一点需要注意,如果then不是一个函数的话,那么then的下一个链式调用采用的是then接受到的值
                nextTask(result)
            }
        } catch (err) {
            nextReject(err)
        }
    }
    then(resolve, reject) {
        const { _status } = this;
        return new MyPromise((nextResolve, nextReject) => {
          	//进行队列的预处理,主要是then结果判断,为了保证正确的给链式调用的下一级传参
            const _fulfilledHandle = this._handleCheck.bind(this, resolve, nextResolve, nextResolve, nextReject)
            const _rejectedHandle = this._handleCheck.bind(this, reject, nextReject, nextResolve, nextReject)
            
            switch (_status) {
                case STATUS.PENDING:
                    this._fulfilledFun.push(_fulfilledHandle)
                    this._rejectedFun.push(_rejectedHandle)
                    break;
                case STATUS.FULFILLED:
                    _fulfilledHandle()
                    break;
                case STATUS.REJECTED:
                    _rejectedHandle()
                    break;
            }
        })
    }
}



var p = new MyPromise((res, rej) => {
    res(3333)
})


p.then((res) => {
    console.log(1, res)
    return 67
}).then((res) => {
    console.log(5, res)
})
/**
 * 返回结果
  1
  1 3333
  5 67
 */
复制代码

这样一个基本核心的功能就已经实现了。Promise还有一些其他的方法,我们通过这些基础的功能就可以一一实现了。

1、catch

image.png

catch(reject) {
    return this.then(undefined, reject)
}
复制代码

2、finally

image.png
image.png

finally(callback) {
  return this.then(
    value => MyPromise.resolve(callback()).then(() => value),
    error => MyPromise.resolve(callback()).then(() => {throw error})
  )
}
复制代码

3、all

image.png

static all(list) {
  return new MyPromise((res, rej) => {
    const values = [];
    const size = list.length;
    for(let [index, p] of list.entries() ){
      MyPromise.resolve(p).then(v => {
        values[index] = v;
        if(index === size - 1) res(values)
      }).catch(err => rej(err))
    }
  })
}
复制代码

4、race

image.png

static race(list) {
  return new MyPromise((res, rej) => {
    for(let p of list) {
      // 使用MyPromise.resolve 而不是直接p.then 是为了防止p不是一个正常的promise
      MyPromise.resolve(p).then(result => {
        res(result)
      }, error => rej(error))
    }
  })
}
复制代码

5、allSettled

image.png

static allSettled(list) {
  const values = [];
  const size = list.length;
  let count = 0;
  return new MyPromise((res, rej) => {
    const getValues = (val, index) => {
      values[index] = val;
      count++;
      if(count === size) res(values)
    }
    for(let [index, p] of list.entries()) {
      MyPromise.resolve(p).then(result => {
        getValues(result, index)
      }, error => getValues(error, index))
    }
  })
}
复制代码

6、any

image.png

static any(list) {
  const values = [];
  const size = list.length;
  return new MyPromise((res, rej) => {
    for(let [index, p] of list.entries()) {
      MyPromise.resolve(p).then(result => {
        res(result)
      }, error => {
        values[index] = error;
        if(index === size - 1) rej(values)
      })
    }
  })
}
复制代码

以下是完整代码的实现。

const STATUS = Object.freeze({
    PENDING: "pending",
    FULFILLED: "fulfilled",
    REJECTED: "rejected"
})
class MyPromise {
    _status = STATUS.PENDING;
    _value = undefined;
    _fulfilledFun = [];
    _rejectedFun = []
    constructor(handle) {
        if (!this._isFunction(handle)) {
            throw TypeError('arguments must be a function')
        }
        try {
            handle(this._resolve.bind(this), this._reject.bind(this))
        } catch (err) {
            this._reject(err)
        }

    }
    _isFunction(handle)  {
        return typeof handle === 'function'
    }
    _run(tasks) {
        let cb;
        while (cb = tasks.shift()) {
            cb()
        }
    }
    _resolve(val) {
        if (this._status !== STATUS.PENDING) return;
        this._status = STATUS.FULFILLED;
        this._value = val;
        setTimeout(() => { /// 为了模拟异步,实现跟promise一样的异步效果,但是此处其实是宏队列,不是真正的promise微队列
            this._run(this._fulfilledFun)
        }, 0)
    }
    _reject(val) {
        if (this._status !== STATUS.PENDING) return;
        this._status = STATUS.REJECTED;
        this._value = val;
        setTimeout(() => {
            this._run(this._rejectedFun)
        }, 0)
    }
    _handleCheck(preTask, nextTask, nextResolve, nextReject) {
        let result = this._value;
        try {
            if (this._isFunction(preTask)) {
                result = preTask(result)
                if (result instanceof MyPromise) {
                    result.then(nextResolve, nextReject)
                } else {
                    nextTask(result)
                }
            } else {
                nextTask(result)
            }
        } catch (err) {
            nextReject(err)
        }
    }
    
    then(resolve, reject) {
        const { _status } = this;
        return new MyPromise((nextResolve, nextReject) => {
            const _fulfilledHandle = this._handleCheck.bind(this, resolve, nextResolve, nextResolve, nextReject)
            const _rejectedHandle = this._handleCheck.bind(this, reject, nextReject, nextResolve, nextReject)
            switch (_status) {
                case STATUS.PENDING:
                    this._fulfilledFun.push(_fulfilledHandle)
                    this._rejectedFun.push(_rejectedHandle)
                    break;
                case STATUS.FULFILLED:
                    _fulfilledHandle()
                    break;
                case STATUS.REJECTED:
                    _rejectedHandle()
                    break;
            }
        })
    }
    catch(reject) {
        return this.then(undefined, reject)
    }
    finally(callback) {
        return this.then(
            value => MyPromise.resolve(callback()).then(() => value),
            error => MyPromise.resolve(callback()).then(() => {throw error})
        )
    }
    static resolve(value) {
        if (value instanceof MyPromise) return value;
        return new MyPromise(resolve => resolve(value))
    }
    static reject(value) {
        if (value instanceof MyPromise) return value;
        return new MyPromise((resolve, reject) => reject(value))
    }
    static all(list) {
        return new MyPromise((res, rej) => {
            const values = [];
            const size = list.length;
            for(let [index, p] of list.entries() ){
                MyPromise.resolve(p).then(v => {
                    values[index] = v;
                    if(index === size - 1) res(values)
                }).catch(err => rej(err))
            }
        })
    }
    static race(list) {
        return new MyPromise((res, rej) => {
            for(let p of list) {
                // 使用MyPromise.resolve 而不是直接p.then 是为了防止p不是一个正常的promise
                MyPromise.resolve(p).then(result => {
                    res(result)
                }, error => rej(error))
            }
        })
    }
    static allSettled(list) {
        const values = [];
        const size = list.length;
        let count = 0;
        return new MyPromise((res, rej) => {
            const getValues = (val, index) => {
                values[index] = val;
                count++;
                if(count === size) res(values)
            }
            for(let [index, p] of list.entries()) {
                MyPromise.resolve(p).then(result => {
                    getValues(result, index)
                }, error => getValues(error, index))
            }
        })
    }
    static any(list) {
        const values = [];
        const size = list.length;
        return new MyPromise((res, rej) => {
            for(let [index, p] of list.entries()) {
                MyPromise.resolve(p).then(result => {
                    res(result)
                }, error => {
                    values[index] = error;
                    if(index === size - 1) rej(values)
                })
            }
        })
    }
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享