手寫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)
      });

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM