zoukankan      html  css  js  c++  java
  • 手写promise

    promise规范
    1、当实例化Promise时会立即执行
    2、已经是成功态或是失败态不可再更新状态
    3、让Promise支持异步
    我们可以参照发布订阅模式,在执行then方法时如果还在等待态(pending),就把回调函数临时寄存到一个数组里,当状态发生改变时依次从数组中取出执行就好了。
    4、链式调用
    5、每个then方法都返回一个新的Promise对象(原理的核心)
    6、如果then方法中显示地返回了一个Promise对象就以此对象为准,返回它的结果
    7、如果then方法中返回的是一个普通值(如Number、String等)就使用此值包装成一个新的Promise对象返回。
    8、如果then方法中没有return语句,就视为返回一个用Undefined包装的Promise对象
    9、若then方法中出现异常,则调用失败态方法(reject)跳转到下一个then的onRejected
    10、如果then方法没有传入任何回调,则继续向下传递(值的传递特性)。
    function _Promise(executor){
          var _this = this;
          this.status = 'pending';      //status属性保存了Promise对象的状态
          this.value = undefined;       //一个Promise对象执行成功了要有一个结果,它使用value属性保存
          this.reason = undefined;      //也有可能由于某种原因失败了,这个失败原因放在reason属性中保存
          this.onFulfilledFunc = [];   //保存成功回调
          this.onRejectedFunc = [];    //保存失败回调
          executor(resolve, reject);    //其执行器函数(executor)会立即执行
    
          //当Promise对象已经由pending状态改变为了成功态(resolved)或是失败态(rejected)就不能再次更改状态了
          function resolve(value){  
              if(_this.status === 'pending'){
                _this.value = value;//保存成功结果
                _this.onFulfilledFunc.forEach(fn=>fn(value));
                _this.status = 'resolved';
              }
          }
    
          function reject(reason){
              if (_this.status === 'pending') {
                _this.value = reason;//保存失败原因
                _this.onRejectedFunc.forEach(fn=>fn(value));
                _this.status = 'reject';
              }
          }
        }
    
        _Promise.prototype.then = function(onFulfilled,onRejected){
          console.log(onFulfilled)
          console.log(this)
    
          //不论何种情况then都返回Promise对象,所以我们就实例化一个新re_promise并返回
          var re_promise = new _Promise(
              (resolve,reject)=>{
                  //等待态,此时异步代码还没有走完
              if (this.status === 'pending') {
                if (typeof onFulfilled === 'function') {
                  this.onFulfilledFunc.push(()=>{
                    setTimeout(()=>{
                      try{
                        let x = onFulfilled(this.value);
                        resolvePromise(re_promise, x, resolve, reject)
                      }
                      catch(e){
                        reject(e)
                      }
                    },0)
                  });
    
                }
    
                if (typeof onRejected === 'function') {
                  this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                      try {
                        let x = onRejected(this.reason);
                        resolvePromise(re_promise, x, resolve, reject);
                      } catch (e) {
                        reject(e);
                      }
                    }, 0)
                  });
    
                }
              }
    
              if (this.status === 'resolved') {
                //判断参数类型,是函数再执行
                console.log(typeof onFulfilled)
                if (typeof onFulfilled === 'function') {
                  setTimeout(() => {
                    try {
                      let x = onFulfilled(this.value);
                      resolvePromise(re_promise, x, resolve, reject);
                    } catch (e) {
                      reject(e);
                    }
                  }, 0);
                }
              }
              if (this.status === 'rejected') {
                //判断参数类型,是函数再执行
                if (typeof onRejected === 'function') {
                  setTimeout(() => {
                    try {
                      let x = onRejected(this.reason);
                      resolvePromise(re_promise, x, resolve, reject);
                    } catch (e) {
                      reject(e);
                    }
                  }, 0);
                }
              }
              }
          )
    
          //接下来就处理根据上一个then方法的返回值来生成新Promise对象
          /**
           * 解析then返回值与新Promise对象
           * @param {Object} re_promise 新的Promise对象 
           * @param {*} x 上一个then的返回值
           * @param {Function} resolve re_promise的resolve
           * @param {Function} reject re_promise的reject
           */
          function resolvePromise(re_promise,x,resolve,reject){
            if (re_promise === x) {
              //不能返回自己的promise对象
              reject(new TypeError('Promise发生了循环引用'));
            }
            if(x !== null && (typeof x ==='object' || typeof x ==='function')){
              try{
                let then = x.then; //取出then方法引用
                if(typeof then === 'function'){
                  //如果then,则认为then为一个promise对象
                  let y = then.call(x, (y) => {
                    //递归调用,传入y若是Promise对象,继续循环
                    resolvePromise(re_promise,y,reslove,reject);
                  }, (r) => {
                    reject(r);
                  });
                }
                else{
                  resolve(x)
                }
              }catch(e){
                //防止出现取then时报错,例如使用Object.defineProperty()
                reject(e)
              }
            }
            else{
              resolve(x);
            }
          }
    
          return re_promise
        }
    
        //可是还有一个很大的问题,目前此Promise还不支持异步代码,如果Promise中封装的是异步操作,then方法无能为力:
        let p = new _Promise((resolve, reject) => {
            // resolve('同步');
            setTimeout(() => {
              resolve('异步');
            },1500);
          })
          // }).then(data=>console.log(data));
    
          // p.then(data => console.log(data)); //没有任何结果
          // p.then(function(data){
          //   console.log(data)
          // }); //没有任何结果
    
          p.then(data => {return 2;}).then(data=>{
            console.log(data)
          });

  • 相关阅读:
    C++链式队列基本操作
    C++链栈基本操作
    C++顺序栈基本操作
    C++链表基本操作
    C/C++/JAVA
    C++操作链表
    How Many Maos Does the Guanxi Worth
    Heavy Transportation
    Frogger
    Til the Cows Come Home(Dijkstra)
  • 原文地址:https://www.cnblogs.com/qdcnbj/p/12862689.html
Copyright © 2011-2022 走看看