手写Promise 一目了然 (另附完整demo)

244 阅读4分钟

手写Promise

手写Promise之前, 我们先看看Promise有哪些方法需要我们封装:

Promise常用方法

详情点击查看链接, 这里只是简单的说明

常用方法说明
executor(resolve, reject)执行器, Promise的参数, 包含resolve和reject两个回调函数
resolveexecutor的回调, 接收成功的数据
rejectexecutor的回调,接收失败的数据
.then(onResolved, onRejected)Promise原型链上的方法,返回Promise, 处理成功和失败情况
.catch(onRejectd)Promise原型链上的方法, 返回Promise, 处理失败情况
onResolved.then()传入的回调, 处理接收到的成功的数据
onRejected.then()和.catch()传入的回调, 处理接收到的失败的数据
.resolve静态方法, 返回一个以给定值解析后的Promise对象
.reject静态方法, 返回一个带有拒绝原因的Promise对象。
.all静态方法, 接收promise数组 只返回一个Promise实例, 返回的结果顺序不变
.race静态方法, 接收promise数组 返回第一个处理完的Promise的结果

Promise结构

Promise
├── 实例属性↓
├── PromiseState // 当前Promise状态属性
├── PromiseREsult // 存储结果数据
├── resolve()
├── reject()
├
├── 原型方法 ↓
├── Promise.prototype.then(onResolved, onRejected)
├── Promise.prototype.catch(onRejected)
├
├── 静态方法 ↓
├── Promise.all()
├── Promise.race()
├── Promise.resolve()
├── Promise.reject()

封装resolve和reject方法

特点:

  1. Promise的PromiseState状态属性只能被修改一次
  2. 存储接收的数据PromiseResult
  3. 如果.then()或.catch()有传异步回调进来, 那就要在返回Promise对象后去执行(settimeout开启新的进程)
function Promise(executor) {
    const _this = this;
    _this.PromiseState = PENDING; // Promise的状态属性
    _this.PromiseResult = undefined; // 保存结果数据
    _this.callbacks = []; // 保存.then()和.catch()传进来的待执行的回调函数 结构: { onResolved: Function; onRejected: Function; }

    try {
        executor(resolve, reject);
    } catch (e) {
        reject(e);
    }

    // 成功时, resolve回调 接收响应数据
    function resolve(data) {
        if (_this.PromiseState !== PENDING) return;
        _this.PromiseState = RESOLVED;
        _this.PromiseResult = data;
        // 执行.then传进来的异步回调(在返回Promise之后)
        if (_this.callbacks.length) {
            setTimeout(() => {
                _this.callbacks.forEach((callbackObj) => {
                    callbackObj.onResolved(data); // 执行成功的处理函数
                });
            });
        }
    }

    // 失败时, reject回调 接收失败信息
    function reject(error) {
        if (_this.PromiseState !== PENDING) return;
        _this.PromiseState = REJECTED;
        _this.PromiseResult = error;
        // 执行.then和.catch传进来的异步回调(在返回Promise之后)
        if (_this.callbacks.length) {
            setTimeout(() => {
                _this.callbacks.forEach((callbackObj) => {
                    callbackObj.onRejected(error); // 执行失败的处理函数
                });
            });
        }
    }
}

核心难点——封装prototype.then()

步骤:

step1: 返回一个Promise实例

​ **step2: **根据Promise的pending状态, 先保存onResolved和onRejectd, 再执行

​ (2.1) 'pending': 存入onResolved和onRejectd

​ (2.2) 'rejected': 执行onRejectd

​ (2.3) 'resolved': 执行onResolved

↓↓↓ 为确保能够一直.then链式调用下去(让下一次的.then始终能拿到上一次的结果), 我们要对上一次回调执行得到的结果进行处理

step3: 处理 执行onResolved或onRejectd得到的结果:

​ (3.1) 结果是异常 → reject(error)

​ (3.2) 结果是promise → 取出这个promise的结果, 当做当前这个return new Promise的结果

​ (3.3) 结果是非promise → resolved(data)

Snipaste_2021-08-30_22-28-51.jpg

Promise.prototype.then = function (onResolved, onRejected) {
    const _this = this;
    // step 1:
    return new Promise(function (resolve, reject) {
        // 检查参数, 两个参数必须都是函数: (形参data/error 其实都是_this.PromiseResult的结果)
        onResolved = typeof onResolved === 'function' ? onResolved : data => data;
        onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error;}

        // step 3(可以提取成公共处理步骤):
        function handle(callback) {
            try {
                const res = callback(_this.PromiseResult);
                if (res instanceof Promise) {
                    res.then(resolve, reject); // step 3.2
                    // res.then((data) => resolve(data), (error) => reject(error)); // 写法同上
                } else {
                    resolve(res); // step 3.3
                }
            } catch (error) {
                reject(error); // step 3.1
            }
        }

        // step 2:
        if (_this.PromiseState === RESOLVED) {
            setTimeout(() => { handle(onResolved)});
        } else if (_this.PromiseState === REJECTED) {
            setTimeout(() => { handle(onRejected)});
        } else {
            _this.callbacks.push({
				onResolved() {
					handle(onResolved);
				},
                onRejected() {
                    handle(onRejected);
                },
            })
        }
    })
};

// .then封装完, .catch就可以直接使用了:
Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected)
};

Promise.resolve和Promise.reject

Promise.resolve:

返回一个以给定值(resolve的参数)解析后的Promise

  1. 如果resolve的参数是一个promise, 则返回这个Promise
  2. 如果resolve的参数是一个非promise, (比如固定值, Promise.resolve(1) ), 则返回带有这个值的Promise
Promise.resolve = function (value) {
    return new Promise((resolve, reject) => {
        // 1. value 本身也是一个Promise, 走.then, 用resolve或reject去接收value的结果
        if (value instanceof Promise) {
            value.then(resolve, reject);
        } else {
            // 2. value 是一个除Promise外的其他类型, 走resolve
            resolve(value);
        }
    });
};
// reject就直接用reject去接收就可以了
Promise.reject = function (error) {
    return new Promise((resolve, reject) => {
        reject(error)
    })
};

Promise.all

特点:

  1. 接收一个promise数组, 只返回一个Promise实例, 结果是一个数组
  2. 结果的顺序不能变
  3. 只有所有的promise都成功, 才返回成果的结果, 否则将返回第一个失败的结果
Promise.all = function (promiseList) {
    const dataList = new Array(promiseList.length);
    let successCount = 0;
    return new Promise((resolve, reject) => {
        promiseList.forEach((p, index) => {
            // 考虑到p可能不是一个promise
            Promise.resolve(p).then(
                data => {
                    // 数据顺序需要保持一致
                    dataList[index] = data;
                    successCount++;
                    // 检查是否全部成功
                    if (successCount === promiseList.length) {
                        resolve(dataList);
                    }
                },
                // 失败就返回第一个失败的结果
                error => reject(error)
            )
        });
    });
};

promise.race

特点:

  1. 返回Promise实例
  2. 返回第一个成功或失败的promise
Promise.race = function (promiseList) {
    return new Promise((resolve, reject) => {
        promiseList.forEach((p, index) => {
            // 考虑到p可能不是一个promise
            Promise.resolve(p).then(
                data => resolve(data),
                // 失败就返回第一个失败的结果
                error => reject(error)
            )
        });
    });
};

篇幅有限, 想查看完整的Promise demo, 以及class版本的童鞋 可以移步这里☞ github地址

好啦, 今天就分享到这里, 希望能对大家有所帮助~!