探秘Promise原理-带你原生实现Es6之Promise (从0到1)

Promise是什么

Promise 是异步编程的一种解决方案。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

常见传统异步解决方案

1、回调方法

2、事件

3、发布-订阅模式

4、观察者模式

5、其它...

Promise的优势

比传统的解决方案——更合理和更强大。

已逐渐成为现在前端编程中的一种良好编码实践,使其代码结构更加合理、可读性更强。

分步:实现自己的Promise

第一步:从promise的用法中收集它的特点

/*******************************************************************************

  • 分析总结:
  • 1、Promise是一个类, 接受一个执行函数(excurtor),此执行函数会立即执行
  • 2、excurtor函数接受两个方法参数, 分别为resolve、reject;调用时可以传入一个值,此值可以是任意值
  • 3、调用resolve,会执行then方法的成功回调(第一个参数)
  • 4、调用reject,会执行then方法的失败回调(第二个参数)
  • 5、promise有三种状态:pending(初始状态)、resolved、rejected;
  • 只能从pending变为resolved或rejeted, 状态一旦确定,不能再次改变
  • 6、每个实例都有then方法,可以多次then, then方法的参数个数(2个,1个,0个),当then为空时,会将状态传递下去,给下一次then
  • 7、调用then时,如果已成功,则执行成功回调,并把成功的内容传递过去;反之,失败亦然;
  • 8、如果类的执行函数执行抛出异常时,则会走失败回调,且传入异常
  • 9、调用then时,会返回一个新的promise,实现链式调用;
  • 10、then执行时,如果回调有返回结果,则会执行下一次的成功回调,并把值传入;如果抛出了异常,则会走下一次的失败回调
  • 11、失败了也可以再成功,如没有返回值,则返回undefined
  • 12、catch会捕获没有捕获到的错误
  • 13、如果回调中返回的是一个promise, 会等待其执行,来决定走下一次的成功还是失败回调
  • 14、自己不能等待自己完成,否则会报一个“循环引用”的类型错误
  • 15、为什么链接调用时不能返回this? 因为状态确定后就不能再改变 ******************************************************************************/

第二步:Promise骨架 (简洁版)

/* ----------------------------------------------------------------------------
 * Promise 骨架板
 --------------------------------------------------------------------------- */
const states = {
    PENDING  : 'pending',
    FULFILLED: 'fulfilled',
    REJECTED : 'rejected'
}

class Promise {
    /**
     * [ 构造函数 ]
     * @param  {[function]} excurtor [执行函数]
     * @return {[undefined]} undefined
     */
    constructor (excurtor) {
        let self = this;

        this.status      = states.PENDING; // 当前状态
        this.value       = undefined;      // 成功的内容
        this.reason      = undefined;      // 失败的原因
        this.onFulfilled = [];             // 存储成功回调
        this.onRejected  = [];             // 存储失败回调

        // 成功方法
        function resolve (value) {
            let onFulfilled = self.onFulfilled;

            // 判断状态是否为pending,只有此状态时,才可以发生状态改变
            if (self.status === states.PENDING) {
                self.status = states.FULFILLED;
                self.value = value;

                if (onFulfilled.length) {
                    onFulfilled.forEach(fn => {
                        fn();
                    });
                }
            }
        }

        // 失败方法
        function reject (reason) {
            let onRejected = self.onRejected;

            // 判断状态是否为pending,只有此状态时,才可以发生状态改变
            if (self.status === states.PENDING) {
                self.status = states.REJECTED;
                self.reason = reason;

                if (onRejected.length) {
                    onRejected.forEach(fn => {
                        fn()
                    });
                }
            }
        }

        // 立即调用执行函数,并捕获异常
        try {
            excurtor(resolve, reject);
        } catch (e) {
            reject(e); // 捕获到执行函数异常后,直接执行失败回调
        }
    }

    /**
     * [ 实例方法: then ]
     * @param  {[function]} onFulfilled [成功回调]
     * @param  {[function]} onRejected  [失败回调]
     * @return {[undefined]}  undefined
     */
    then (onFulfilled, onRejected) {
        let self = this;

        // 状态已改变为成功时,则立即执行
        if (self.status === states.FULFILLED) {
            onFulfilled(self.value);
        }

        // 状态已改变为失败时,则立即执行
        if (self.status === states.REJECTED) {
            onRejected(self.reason);
        }

        // 处理异步情况,先存在起来,等状态改变再执行相应回调
        if (self.status === states.PENDING) {
            self.onFulfilled.push(() => {
                onFulfilled(self.value);
            });
            self.onRejected.push(() => {
                onRejected(self.reason);
            });
        }
    }
}

// 测试例子 ---------------------------------------------------------------------
let promise = new Promise((resolve, reject) => {
    //setTimeout(() => {
        resolve(100);
    //}, 1000)
});

promise.then(
    value => console.log(value),
    reason => console.log(`fail: ${ reason }`)
);
复制代码

第三步:Promise完整版

/* ----------------------------------------------------------------------------
 * Promise 完整版
 --------------------------------------------------------------------------- */
const states = {
   PENDING  : 'pending',
   FULFILLED: 'fulfilled',
   REJECTED : 'rejected'
}

class Promise {
   /**
    * [ 构造函数 ]
    * @param  {[Function]} excurtor [执行函数]
    * @return {[Undefined]} undefined
    */
   constructor (excurtor) {
       let self = this;

       this.status      = states.PENDING; // 当前状态
       this.value       = undefined;      // 成功的内容
       this.reason      = undefined;      // 失败的原因
       this.onFulfilled = [];             // 存储成功回调
       this.onRejected  = [];             // 存储失败回调

       // 成功方法
       function resolve (value) {
           let onFulfilled = self.onFulfilled;

           // 判断状态是否为pending,只有此状态时,才可以发生状态改变
           if (self.status === states.PENDING) {
               self.status = states.FULFILLED;
               self.value = value;

               if (onFulfilled.length) {
                   onFulfilled.forEach(fn => {
                       fn();
                   });
               }
           }
       }

       // 失败方法
       function reject (reason) {
           let onRejected = self.onRejected;

           // 判断状态是否为pending,只有此状态时,才可以发生状态改变
           if (self.status === states.PENDING) {
               self.status = states.REJECTED;
               self.reason = reason;

               if (onRejected.length) {
                   onRejected.forEach(fn => {
                       fn()
                   });
               }
           }
       }

       // 立即调用执行函数,并捕获异常
       try {
           excurtor(resolve, reject);
       } catch (e) {
           reject(e); // 捕获到执行函数异常后,直接执行失败回调
       }
   }

   /**
    * [ 实例方法: then ]
    * @param  {[Function]} onFulfilled [成功回调]
    * @param  {[Function]} onRejected  [失败及异常回调]
    * @return {[Object]}  promise2
    */
   then (onFulfilled, onRejected) {
       // 补全参数,实现往下传递
       onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
       onRejected = typeof onRejected === 'function' ? onRejected : error =>{ throw error };

       let self = this;
       let promise2;

       promise2 = new Promise((resolve, reject) => {
           // 状态已改变为成功时,则立即执行
           if (self.status === states.FULFILLED) {
               setTimeout(() => { // 此定时器确保回调方法在异步中执行的,也方便进行promiseA+规范测试
                   // try catch 用来捕获回调方法中抛出的异常
                   try {
                       let x = onFulfilled(self.value);
                       resolvePromise(promise2, x, resolve, reject);
                   } catch (e) {
                       reject(e);
                   }
               });
           }

           // 状态已改变为失败时,则立即执行
           if (self.status === states.REJECTED) {
               setTimeout(() => { // 同上
                    // 同上
                   try {
                       let x = onRejected(self.reason);
                       resolvePromise(promise2, x, resolve, reject);
                   } catch (e) {
                       reject(e);
                   }
               }, 0);
           }

           // 处理异步情况,先存在起来,等状态改变再执行相应回调
           if (self.status === states.PENDING) {
               self.onFulfilled.push(() => {
                   setTimeout(() => {  // 同上
                        // 同上
                       try {
                           let x = onFulfilled(self.value);
                           resolvePromise(promise2, x, resolve, reject);
                       } catch (e) {
                           reject(e);
                       }
                   }, 0);
               });
               self.onRejected.push(() => {
                   setTimeout(() => {  // 同上
                        // 同上
                       try {
                           let x = onRejected(self.reason);
                           resolvePromise(promise2, x, resolve, reject);
                       } catch (e) {
                           reject(e);
                       }
                   }, 0);
               });
           }
       });

       return promise2;
   }

   /**
    * [ 实例方法:catch ]
    * @param  {[Function]} onRejected [失败及异常回调]
    * @return {[Object]}   promise
    */
   catch (onRejected) {
       return this.then(null, onRejected);
   }

   /**
    * [ 静态方法(由类调用):all ]
    * @param  {[Array]} promises [由promise组成的数组]
    * @return {[Object]} promise
    */
   static all (promises) {
       let res = [];
       let count = 0;
       let length = promises.length;

       return new Promise((resolve, reject) => {
           promises.forEach((promise, index) => {
               promise.then(
                   value => {
                       res[index] = value;
                       if (++count === length) {
                           resolve(res);
                       }
                   },
                   reject
               );
           });
       });
   }

   /**
    * [ 静态方法(由类调用)race ]
    * @param  {[Array]} promises [由promise组成的数组]
    * @return {[Object]} promise
    */
   static race (promises) {
       return new Promise((resolve, reject) => {
          promises.forEach(promise => {
              promise.then(resolve, reject);
          })
       });
   }
}

function resolvePromise(promise2, x, resolve, reject) {
    // 自己不能等待自己的状态改变
    if (promise2 === x) {
        return reject(new TypeError('循环引用'));
    }

    let called; // 标识位,要么成功,要么失败;
    let typeX = typeof x;

    // 判断x的类型是否为对象或者函数且不为null
    if (x !== null && (typeX === 'object' || typeX === 'function')) {
        try {
            let then = x.then; // 获取then方法; 此处的try用于防止第三方库中获取值会抛错

            if (typeof then === 'function') { // 说明返回的是promise事例
                // 执行then方法,并将this指向x
                then.call(x, y => {
                    if (called) return;
                    called = true;
                    // 如果返回的还是promise, 则将会继续递归调用
                    resolvePromise(promise2, y, resolve, reject);
                }, e => {
                    if (called) return;
                    called = true;
                    reject(e);
                });
            } else { // x为变通对象时,直接成功
                resolve(x);
            }
        } catch (e) {
            if (called) return;
            called = true;
            reject(e);
        }
    } else {
        resolve(x);
    }
}

// 为了方便promiseA+规范测试
Promise.defer = Promise.deferred = function () {
    let dtd = {};
    dtd.promise = new Promise((resolve, reject) => {
        dtd.resolve = resolve;
        dtd.reject = reject;
    });
    return dtd;
};


module.exports = Promise;



// 测试例子 ---------------------------------------------------------------------
let promise = new Promise((resolve, reject) => {
   resolve(1000);
   //reject(100);
});

promise
.then(
   value => {
       console.log('then:', value);
       return new Promise((resolve, reject) => {
           //resolve(199);
           reject('error123');
       });
   },
   reason => console.log(`fail: ${ reason }`)
)
.then(
   value => console.log(value),
   reason => console.log(`fail: ${ reason }`)
);

Promise.all([
    new Promise((resolve, reject) => {
        resolve(1);
    }),
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(2);
        }, 1000);
    }),
    new Promise((resolve, reject) => {
        resolve(3);
        //reject('出错了')
    })
]).then(
    value => console.log(value),
    e => console.log(e)
);

复制代码

Promise/A+ 参考资料及测试插件

1、PromiseA+规范说明网址

2、promises-aplus-tests

简介:此包模块可以帮助我们测试自已写的Promise是否符合上面的规范。

命令: promises-aplus-tests promise.js

说明:命令后的文件名(promise.js) 为你自己定义的文件名

你可能感兴趣的:(探秘Promise原理-带你原生实现Es6之Promise (从0到1))