Promise源码详解

163 阅读4分钟

Promise设计模式

=>ES6提供的内置类,基于Promise可以有效的管理JS中的异步编程解决传统的异步编程+回调函数导致的“回调地狱”的问题,基于Promise进行异步管控的设计模式叫PROMISE设计模式

高阶函数(满足以下任意一个)

  • ①一个函数的参数中有函数,那么当前这个函数就是高阶函数
  • ②如果一个函数返回了一个函数,那么当前这个函数就是高阶函数

函数柯理化

  • 目的: 利用闭包机制,把一些信息预先存储下来。细化函数功能,让他变得更具体一些
  • 闭包: 函数执行会形成私有的上下文的机制就称为闭包
    • 闭包的作用: 在这个上下文中有一些私有的变量AO,和外界的变量不会有冲突、
    • 保存作用 在上下文中的返回值被外界占用,会形成不销毁的上下文,把所用到的信息存起来
    • 缺点: 导致堆栈内存消耗过大,导致内存泄露,影响页面的运行效率,需要合理利用闭包

解析Promise运行机制

  • let p = new Promise(executor)
    • executor为一个函数
    • 在创建实例的时候就把executor执行
    • 并为exector传递俩个参数,都为函数 executor(RESOLVE,REJECT)
    • executor(resolve,reject){管控异步代码}
    • PROMISE实例p拥有俩个值:①PromiseStatus ②PromiseValue
      • ①PromiseStatus 有三个状态:pending(准备状态)、fulfilled(操作成功完成)、resolved成功状态(在异步操作成功的时候,通过执行resolve函数,可以把当前的Promise实例状态变为成功态)、rejected失败状态(在异步操作失败的时候,通过执行reject函数,可以把当前的Promise实例状态变为失败态)
      • ②PromiseValue: 是Promise实例的值,不论执行哪个函数,都可以将值传递给当前实例
      • 通过RESOLVE、REJECT可以控制当前实例的状态和值。
  • p.then([状态为成功时执行的函数],[状态为失败时执行的函数]),通过控制p的状态就是为了控制then中的哪个方法执行。
    • 俩个函数参数接收的分别是p的PromiseValue
    • then中的方法只会在实例状态为成功或者失败的时候才会执行
  • Promise中的then链
    • 用法:p.then().then()....
    • 每一次执行then都会返回一个Promise实例
    • 下一个then链返回的Promise实例状态由上一个then中的函数返回的结果决定
      • 只要不报错,不论哪个方法执行,下一个then的Promise都为成功态,函数执行返回的值作为下一个then的Promise实例初始值,没有返回则为undefined
      • 只要上一个then中报错,则下一个then实例状态为失败态
    • 当上一个then中又返回一个新的Promise实例,即exector中有new Promise(),则会等待新的执行结果作为下一个then实例的初始状态
    • then中不写RESOLVE,REJECT其中一个函数,Promise会补充一个函数
    • 为了代码的可读性,规定catch()在失败的时候执行,then()在成功的时候执行,
    catch(){
        reason=>{...}
    }
    //代替
    then(null,reason=>{...})
    

Promise作为普通对象=>静态私有属性方法

  • Promise.all()
  • Promise.race()
  • Promise.resolve()
  • Promise.reject()

Promise作为类-原型上共有的属性和方法

  • Promise.prototype.then()
  • Promise.prototype.catch()
  • Promise.prototype.finally()

Promise语法糖

替代then链实现同步的异步等待效果。

  • async: async修饰符可以让一个普通的函数返回的结果变成一个Promise实例

  • await: await修饰符等待Promise成功,并获取到结果,再往下执行。

    • async和await同时使用
    • 只有await等待的实例的状态变为成功,才会把返回的结果赋值给变量,执行下边的代码
    • await弊端:如果Promise实例状态为失败,下边的代码不再执行(Uncaught(in Promise)

手写源码

/*
 * Promise A+:Promise的设计规范
 */
class MyPromise {
    constructor(executor) {
        // 初始属性值
        this.status = 'pending';
        this.value = undefined;
        this.resolvedArr = [];
        this.rejectedArr = [];

        // 改变状态的函数
        let changeStatus = (status, result) => {
            if (this.status !== 'pending') return;
            this.status = status;
            this.value = result;
            let arr = status === 'rejected' ? this.rejectedArr : this.resolvedArr;
            arr.forEach(item => (typeof item === 'function' ? item(this.value) : null));
        };
        let resolve = result => {
            if (this.resolvedArr.length > 0) {
                changeStatus('resolved', result);
                return;
            }
            let delayTimer = setTimeout(() => {
                clearTimeout(delayTimer);
                changeStatus('resolved', result);
            }, 0);
        };
        let reject = reason => {
            if (this.rejectedArr.length > 0) {
                changeStatus('rejected', reason);
                return;
            }
            let delayTimer = setTimeout(() => {
                clearTimeout(delayTimer);
                changeStatus('rejected', reason);
            }, 0);
        };

        // 异常捕获处理
        try {
            executor(resolve, reject);
        } catch (error) {
            reject(error);
        }
    }

    then(resolvedFn, rejectedFn) {
        if (typeof resolvedFn !== 'function') {
            resolvedFn = result => {
                return result;
            };
        }
        if (typeof rejectedFn !== 'function') {
            rejectedFn = reason => {
                // throw new Error(reason);
                return new MyPromise((resolve, reject) => {
                    reject(reason);
                });
            };
        }

        // then链:返回一个新的Promise实例
        return new MyPromise((resolve, reject) => {
            this.resolvedArr.push(() => {
                try {
                    let x = resolvedFn(this.value);
                    x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
                } catch (error) {
                    reject(error);
                }
            });
            this.rejectedArr.push(() => {
                try {
                    let x = rejectedFn(this.value);
                    x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
                } catch (error) {
                    reject(error);
                }
            });
        });
    }

    catch (rejectedFn) {
        // catch(rejectedFn) === then(null,rejectedFn)
        return this.then(null, rejectedFn);
    }

    /* 静态方法 */
    static resolve(result) {
        return new MyPromise(resolve => {
            resolve(result);
        });
    }

    static reject(reason) {
        return new MyPromise((_, reject) => {
            reject(reason);
        });
    }

    static all(arr) {
        return new MyPromise((resolve, reject) => {
            let index = 0,
                results = [];
            for (let i = 0; i < arr.length; i++) {
                let item = arr[i];
                if (!(item instanceof MyPromise)) continue;
                item.then(result => {
                    index++;
                    results[i] = result;
                    if (index === arr.length) {
                        resolve(results);
                    }
                }).catch(reason => {
                    // 只要有一个失败,整体就是失败
                    reject(reason);
                });
            }
        });
    }
}
module.exports = MyPromise;