美文网首页
手写一个符合Promise/A+规范的Promise

手写一个符合Promise/A+规范的Promise

作者: 成熟稳重的李先生 | 来源:发表于2019-10-14 16:44 被阅读0次

    Promise的基本概念:

    Promise使异步脱离了回调地狱,可以更优雅的操作异步函数的执行结果。究其根本,不过是使用了发布/订阅来达到这一效果。

    • 1.promise有三种状态, “pending”,“resolved”, “rejected”。只能由“pending”转化为“resolved”或者由“pending”转化为“rejected”。状态改变后,不能再次改变!
    • 2.回顾下发布/订阅模式,再对照promise。即then时,将成功和失败函数分别保存到订阅列表。执行原函数(一般是异步),当成功/失败后,分别调用成功/失败保存的函数
    function Promise(executor){  // executor是用户要执行的异步方法(立即执行)
      this.status = "pending";  // 初始状态
      this.value = undefined;  //成功的值
      this.reason = undefined;  // 失败的值(原因)
      this.onResolvedCallbacks = [];  // “成功”的订阅者
      this.onRejectedCallbacks = [];  // “失败”的订阅者
      let self = this;
      function resolve(value){  // resolve/reject这两个方法,都是用户主动调用的
        self.status = "resolved";  // 改变promise状态  
        self.value = value;   //成功的值
        self.onResolvedCallbacks.forEach(fn => fn()); // 发布这个“成功”的消息
      }
      function reject(reason){
        self.status = "rejected"; 
        self.reason = reason;  // 失败的原因
        self.onRejectedCallbacks.forEach(fn => fn()); // 发布这个“失败”的消息
      }
      try {
        executor(resolve, reject);  // 立即执行用户的异步方法,并且将这两个出发函数传递给用户
      }catch(e){
        reject(e); // 异常也视为失败
      }
    }
    Promise.prototype.then = function(onFulfilled, onRejected){
      onFulfilled = (typeof onFulfilled === "function") ? onFulfilled : val => val;  // promise有向下传递的特性,如果不处理,直接将值传递给下一层
      onRejected = (typeof onRejected === "function") ? onRejected : reason => {
        throw reason;
      };
      let self = this;
      let promise2 = new Promise((resolve, reject) => {  // 这就是为什么可以一直then(因为then返回的还是一个promise)
        if(self.status === "resolved"){  // 如果这个异步已经成功,那么直接调用
          setTimeout(() => { //这里使用setTimeout是,因为在下边代码中要使用promise2,如果是同步的话,就拿不到promise2,因此需要将其放入下一个队列中
            try {
              let x = onFulfilled(self.value); // 执行成功的函数(有可能它还返回promise,因此如下有函数“resolvePromise”)
              resolvePromise(promise2, x, resolve, reject); //处理这个结果
            }catch(e){
              reject(e); // 如果函数执行失败,那么会走向下一个then的失败状态
            }
          }, 0)
        }else if(self.status === "rejected"){
          setTimeout(() => {
            try {
              let x = onRejected(self.reason);
              resolvePromise(promise2, x, resolve, reject);
            }catch(e){
              reject(e);
            }
          }, 0)
        }else{
          self.onResolvedCallbacks.push(() => {
            setTimeout(() => {
              try {
                let x = onFulfilled(self.value);
                resolvePromise(promise2, x, resolve, reject);
              }catch(e){
                reject(e)
              }
            }, 0)
          });
          self.onRejectedCallbacks.push(() => {
            setTimeout(() => {
              try {
                let x = onRejected(self.reason);
                resolvePromise(promise2, x, resolve, reject);
              }catch(e){
                reject(e);
              }
            }, 0)
          })
        }
      })
      return promise2;
    }
    
    function resolvePromise(promise2, x, resolve, reject) {
      if(promise2 === x){
        return reject(new TypeError("循环引用了"));
      }
      let called = false;
      if(x !== null && (typeof x === "object" || typeof x === "function")){  // 判断x是否为简单类型值,是则直接resolve,否则继续
        try {
          let then = x.then;
          if(typeof then === "function"){ // 判断其是否有then
            then.call(x, y => {
              if(called) return;
              called = true;
              resolvePromise(promise2, y, resolve, reject); // 继续判断这个结果,直到其返回一个简单(非promise)型的值
            }, r => {
              if(called) return;
              called = true;
              reject(r);
            })
          }else{
            //当前then是一个普通对象,直接resolve
            if(called) return;
            called = true;
            resolve(x);
          }
        }catch(e){
          if(called) return;
          called = true;
          reject(e)
        }
      }else{
        if(called) return;
        called = true;
        resolve(x);
      }
    }
    
    Promise.defer = Promise.deferred = function(){  //
      let dfd = {};
      dfd.promise = new Promise((resolve, reject) => {
        dfd.resolve = resolve;
        dfd.reject = reject;
      })
      return dfd;
    }
    
    
    module.exports = Promise;
    

    如何知道是否符合规范呢?
    请查看文档 Promise/A+
    同时,还可以使用包“promises-aplus-tests”来测试你的promise是否符合规范。
    使用方式:

    yarn add promises-aplus-tests -g
    //在你的工作目录下
    promises-aplus-tests  xxx.js  //(共872条测试用例)
    

    相关文章

      网友评论

          本文标题:手写一个符合Promise/A+规范的Promise

          本文链接:https://www.haomeiwen.com/subject/mgcqmctx.html