Promise的封裝


要封裝Promise,首先要了解Promise的使用。

Promise有以下幾個特點:1、Promise是一個構造函數 2、實例化Promise時有兩個回調函數,resolve,reject ,成功執行resolve,失敗執行reject

3、在實例化p的then中有兩個對應的回調函數,第一個回調是resolve執行時觸發,第二個回調是reject執行時觸發4、語法糖catch,就是執行reject的時候,不調用第二個參數,直接鏈式寫catch,像用then一樣【 有坑,異步調用resolve,reject不會觸發 】5、p.then()是Promise類型,p.catch()是Promise類型

先來個簡單的使用實例:

//  使用resolve
let p = new Promise((resolve,reject)=>{ setTimeout(()=> { console.log('延時器代碼執行') // 執行成功 resolve('執行成功') },1000) }) p.then(res=>{ console.log(res) //執行成功 })
//  使用reject
let p = new Promise((resolve,reject)=>{ setTimeout((res)=> { // 模擬執行出錯 if(!res){ // 沒有給res傳參 return reject('執行出錯,沒有參數') } console.log('延時器代碼執行') },1000) }) p.then(res => { console.log(res) //執行成功 },error => { console.log(error) //'執行出錯,沒有參數' 執行出錯執行
    })

封裝同步的Promise

 function myPromise(callback) { //callback 代表( resolve,reject ) => {} // 默認狀態pending,首先沒有執行成功或失敗函數之前狀態是pending
        (this.promiseStatus = 'pending'), this.msg;
     // 用that存當前this的內容 let that
= this // new 自動執行 , 調用callback callback(
      // 定義resolve
function() { // 這里面的arguments,this都是坑,他們兩個都是坑人大咖,兩個都是不定值 that.promiseStatus = 'resolved'; // resolve 的第一個實參 that.msg = arguments[0]; },
       // 定義reject
function() { that.promiseStatus = 'rejected'; // rejected 的第一個實參 that.msg = arguments[0]; } ); } // 往myPromise 原型上添加then方法 myPromise.prototype.then = function() { // 這里的this就是讓實例調用,指向實例的,並不是指向構造函數!!! 花式秀this if (this.promiseStatus == 'resolved') { arguments[0](this.msg); } else if (this.promiseStatus == 'rejected') { arguments[1](this.msg); } }; // 實例化 const p = new myPromise((resolve, reject) => { reject('失敗') }); // 使用then p.then( function (res) { console.log(res); }, function (err) { console.log(err); } );

代碼的思路我會盡量寫詳細寫,以及一些容易出錯的地方,想了幾個小時才發現。。。。。。(無地自容)

  arguments和this值得分析分析。首先是arguments,一開始想省事直接謝了()=>{}代替function(){},乖乖,好了,接下來的1個小時就是找bug時間,()=>{ this.promiseStatus;this.msg = arguments[0] } 請大家盡情笑話我,當時沒有意識到箭頭函數的this是指向上層的this,且不變的,由於arguments和this一樣有不確定性,所以也是指向上層,所以一直糾結為什么arguments不是箭頭函數()=>{ this.promiseStatus;this.msg = arguments[0] } 中 ()里的實參,而是一直是callback ,所以還是老老實實換成function(){this.promiseStatus;this.msg = arguments[0]}

  this引出的2個小時的撓頭瘋狂:剛開始並沒有發現是this的問題,而是封裝完了,運行的時候,不管我在實例里調用resolve還是reject都沒有打印效果,p.then()調用也沒問題,然后找了then方法的定義位置,沒錯啊,上面callback定義的兩個resolve,reject實參函數體我也各自修改了狀態,單詞也沒寫錯,1個多小時過后我終於想看看是不是狀態沒改變,導致then定義方法里的if沒執行,果然不管在實例的時候調用resolve還是reject,狀態都是pending,沒變過,沒道理啊,我眼花了?我繼續往上找,我忽然想起了剛才的argument,忽然面色暗淡,用顫抖的雙手打印了function(){}里的this,呵,window。也就是根本就沒變過實例里的promiseStatus屬性,所以用that存下當前的this,值得一提的是用箭頭函數this就不用that存了,原因在上一段,但是arguments必須又要function(){  }的形式......

異步執行resolve,reject

function myPromise(callback) { //callback 代表( resolve,reject ) => {}
        // 默認狀態pending,首先沒有執行成功或失敗函數之前狀態是pending
        this.promiseStatus = 'pending',
        this.status = [],  //異步時起作用
        this.msg;
     // 用that存當前this的內容
        let that = this
        // new 自動執行 , 調用callback
        callback(
      // 定義resolve
          function() {
            that.promiseStatus = 'resolved';
            // resolve 的第一個實參
            that.msg = arguments[0];
            //判斷存不存在resolve方法  {  } 
            for (const {resolve} of that.status) {
                resolve(that.msg)
            }
          },
       // 定義reject
          function() {
            that.promiseStatus = 'rejected';
            // rejected 的第一個實參
            that.msg = arguments[0];
            for (const {reject} of that.status) {
                reject(that.msg)
            }
          }
        );
      }
      // 往myPromise 原型上添加then方法
      myPromise.prototype.then = function() {
        // 這里的this就是讓實例調用,指向實例的,並不是指向構造函數!!! 花式秀this
        if (this.promiseStatus == 'resolved') {
          arguments[0](this.msg);
          console.log('1234');
          
        } else if (this.promiseStatus == 'rejected') {
          arguments[1](this.msg);
        }else{
            this.status.push({ resolve:arguments[0],reject:arguments[1] })  //實例參數有異步語句的會先執行then
            console.log('yyy');
        }
      };
      // 實例化

      //對於實例化的異步我個人理解為new的過程是這樣的,首先打印123是同步的setTimeout本身是同步的,里面的回調是異步的,是異步就給我等等,先執行then(),由於是自己封裝的then()
    是以原型方法存在,同步調用,調用以后status就變成了[
{ resolve:arguments[0],reject:arguments[1] }],然后回過頭執行setTimeout里的reject,這時候status有了reject
a 所以可以調用then里面的兩個回調也就拿到參數:這里我想了好久。終於想明白了 同步then里面兩個回調是在then中執行,異步是在定義構造函數的callback中的第一個或第二個參數定義中執行。
      //所以在構造函數callback()已經完成,此時還沒運行異步的reject或reject,因為只是聲明函數未執行,當調用
      const p = new myPromise((resolve, reject) => {
          setTimeout(reject,100,'調用失敗')
          console.log(123)
      });
      // 使用then
      p.then(
       function (res) {
         console.log(res); 
       },
       function (err) {
         console.log(err);
       }
      );

有一個問題想了很久,在異步執行resove或reject的時候,setTimeout(   )會不會執行?是先執行setTimeout(   )再執行then還是先執行then,回過頭來執行setTimeout,事實上是先執行then的。緊接着then調用了一次,而那一次由於異步調用所以運行this.status.push({ resolve:arguments[0],reject:arguments[1] }),然后執行異步的reject沒錯。但是這時候還要執行一次then嗎?不執行的話,then里面兩個參數沒法調用,只是聲明,執行的話就執行兩次then有點說不過去

因為問題想了很久,后來才發現很簡單。所以要回顧一下

這里主要說的是異步執行resolve,reject,同步和上面沒區別,也用不到status。

其實把還是在執行順序的問題上。首先執行new的操作,直接進入構造函數執行一遍,接着看到了異步操作和同步操作,先執行同步的打印123沒話講,異步操作呆一邊去先。往下走執行then( )然后這一步因為new中異步執行reject(以代碼來說),所以status就有了一個[{reject:arguments[1]}],此時再去執行new中的reject函數就會執行(不要誤以為執行setTimeout,是里面的回調是異步的)callback對應的第二個參數(函數體),在第二個函數體中for (const {reject} of that.status) {reject(that.msg)}  給then里的第二個參數(也是函數體)傳了實參,所以才能打印出來。

歸根結底   同步執行then的兩個函數參數是在原型中的then方法定義中。

     異步執行then的兩個函數參數是在構造函數callback的兩個函數參數中。


免責聲明!

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



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