手書きで簡単なPromise

7978 ワード

今日は突発的に考えました.自分でPromiseを書いて遊びに来たいです.書くと反応がよくないです.とりあえずPromiseを見てみます.
let pp= new Promise((resolve, reject) => {
	resolve('done');
});

pp.then((value) => {
	console.log(value);
}).catch((e)=>{
    console.log(e);
});
基本的な書き方は大体このようです.Promiseをよく見ると、やはり変です.例えば、パラメータは一つの関数です.この関数は二つのパラメータresoveとrejectがあります.この二つのパラメータも関数です.また、私達が呼出しなければこのPromiseは役に立たないです.thenとcatchの中のものも実行できません.この二つのパラメータはPromiseから提供されたもので、Promise実行プロセスの一部ですが、どうやって書くべきか分かりません.でも、まず行動してから書いたらいいかもしれません.
まず棚を書きます.上の使用例を見てください.基本的に必要なものは必ず次のようなものがあります.構造関数、一つのthen関数、一つのcatch関数、そして上のようにreolveとrejectもPromiseが提供しているはずです.
function helloPromise(cb) {
  cb();
  return {then: this.then, catch: this.catch}; //      
}

helloPromise.prototype.then = function (cb){
  cb();
}

helloPromise.prototype.catch = function (cb){
  cb();
}

helloPromise.prototype.resolve = function (arg){
}

helloPromise.prototype.reject = function (arg){
}
その後、私たちは例を挙げて実行してみましたが、レレスは関数ではないということが分かりました.見に行くと、今のコンストラクタの中でレレスとレジェクトを加えて、このようになりました.
function helloPromise(cb) {
  cb(this.resolve, this.reject);
  return {then: this.then, catch: this.catch};
}
もう一度実行してください.undefinedが出力されています.エラーが発生しました.このundefinedは
pp.then((value) => {
	console.log(value);
})
この文章は印刷しました.このエラーは後ろのcatchです.thenは何も戻っていないので、catchは本体が見つからないです.thenとcatchを変えます.
helloPromise.prototype.then = function (cb){
	cb();
	return new helloPromise(function(resolve, reject) {});
}
もうちょっと実行してください.わあ、少なくとも間違えないように、undefined二つを出力しました.ここまでいくつかの問題があります.
  • はthenを実行した後にcatchを実行して、Promiseの状態はpendingからrejectとreolveの中の一つになるだけで、しかも変化した後に
  • を変えることができません.
  • 私達が書いたPromiseはthenとcatchを同期して実行します.
  • は、reolveとrejectに伝えられた値は、thenとcatchが呼び出されたときに
  • に渡されていません.
    まず状態の問題を解決して、現在の状態を表す変数を加えます.promisestatusは、構造関数に初期状態pendingを追加し、reolve、reject、then、catchに状態判断と状態設定を追加します.
    function helloPromise(cb) {
      this._promiseStatus = 'pending';
      cb(this.resolve, this.reject);
      return {then: this.then, catch: this.catch};
    }
    
    helloPromise.prototype.resolve = function (arg){
      if(this._promiseStatus === 'pending'){
        this._promiseStatus = 'fulfilled';
      }
    }
    
    helloPromise.prototype.then = function (cb){
      if(this._promiseStatus === 'fulfilled'){
        cb();
      }
      return new helloPromise(function(resolve, reject) {});
    }
    
    この時私達が運転してみたら、私達が望む結果とは違って、ここにはたくさんのthisバインディング問題があります.だから、コンストラクタでバインドしてみます.
    function helloPromise(cb) {
      this.resolve = this.resolve.bind(this);
      this.reject = this.reject.bind(this);
      this.then = this.then.bind(this);
      this.catch = this.catch.bind(this);
      
      this._promiseStatus = 'pending';
      cb(this.resolve, this.reject);
      return {then: this.then, catch: this.catch};
    }
    
    運転してください.reolveを発見した時は大丈夫です.rejectに問題があります.thenとcatchで返した値に問題があるので、thisに戻ります.
    helloPromise.prototype.then = function (cb){
      if(this._promiseStatus === 'fulfilled'){
        cb();
      }
      return this;
    }
    
    このように状態もよく伝えられます.(でも、標準と違って顔を隠します.)ここでもう一つの問題があります.catchの行為です.複数のcatchがあれば、元のPromiseは第一個だけ実行します.もしcatchがないなら、エラーは投げられます.この部分はまず見ません.
    まずどのように構造を伝達するかを見てみます.reolveとrejectのパラメータを一つ追加します.promiseValue変数
    helloPromise.prototype.resolve = function (arg){
      if(this._promiseStatus === 'pending'){
        this._promiseStatus = 'fulfilled';
        this._promiseValue = arg;
      }
    }
    
    helloPromise.prototype.then = function (cb){
      if(this._promiseStatus === 'fulfilled'){
        this._promiseValue = cb(this._promiseValue);
      }
      return this;
    }
    
    このように私達の基本的なPromiseの様子はすでにあって、その後私達は誤りを処理しにきて、まず原生のPromiseの行為を見て、間違いの情況はこのようにいくつあります:
  • レシオの前にエラーが発生しました.このようなcatchがあれば、捕獲しません.そして、rejectが誰も接続されていません.thenの内容は
  • を実行しません.
  • レスリング後にエラーが発生しました.このようなcatchがあっても捕れないし、捨てられないです.
  • を食べました.
  • rejectの前にエラーが発生しました.catchがないとエラーを投げます.そしてrejectには誰も来ていません.もしcatchがあったら、エラーは捕獲され、rejectは無視され、catchを入れてもreject
  • を無視できます.
  • rejectの後でエラーが発生しました.catchがないとエラーを投げます.そしてrejectには誰も来ていません.もしcatchがあったら、エラーが食べられます.このcatchは処理されます.もっと多くのcatchを入れても大丈夫です.
  • 上の4の中は全部簡単な情況で、thenとcatchの中で誤りがあるならば、基本的にまた分けてcatchが来るかどうかの情況があって、情況は比較的に多くて、みんなは自分で試してみることができて、比較的に面白いです.
    こちらで処理したのはそんなにひどくないです.簡単に処理して、構造関数の中のコールバックをtry...catchに包んでみました.thenに判断を追加しました.promiseValueはエラーです.直接に過ぎます.thenの関数を実行しないで、catchでエラーをtry...catchします.
    function helloPromise(cb) {
      this.resolve = this.resolve.bind(this);
      this.reject = this.reject.bind(this);
      this.catch = this.catch.bind(this);
      this.then = this.then.bind(this);
    
      this._promiseStatus = 'pending';
      try{
        cb(this.resolve, this.reject);
      }catch(e){
        this._promiseValue = e;
      }
      
      return {then: this.then, catch: this.catch};
    }
    
    helloPromise.prototype.then = function (cb){
      if(toString.call(this._promiseValue) === '[object Error]'){
        return this;
      }
      if(this._promiseStatus === 'fulfilled'){
        try{
          this._promiseValue = cb(this._promiseValue);
        }catch(e){
          this._promiseValue = e;
        }
      }
      return this;
    }
    
    helloPromise.prototype.catch = function (cb){
      if(toString.call(this._promiseValue) === '[object Error]'){
        try{
          this._promiseValue = cb(this._promiseValue);
        }catch(e){
          this._promiseValue = e;
        }
        return this;
      }
      if(this._promiseStatus === 'rejected'){
        try{
          this._promiseValue = cb(this._promiseValue);
        }catch(e){
          this._promiseValue = e;
        }
      }
      return this;
    }
    
    原生と比べてみよう.
  • レスリングの前にエラーが発生しました.キャッチャーがあります.食べられませんでした.
  • レスリング後にエラーが発生しました.同じ
  • です.
  • reject前にエラーが発生しました.catchがないと食べられます.rejectは無視されます.もしcatchがあったら、エラーは捕獲され、rejectは無視され、catchを入れてもreject
  • を無視できます.
  • rejectの後で間違えて、catchがないと食べられます.rejectは無視されます.もしcatchがあったら、エラーは捕獲されます.rejectは無視されます.catchを入れるとrejectを処理します.
  • 複雑な状況はテストしません.とにかく原生とは大きく違っています.
    私達は実はまた面白いことを発見しました.原生のPromiseのresoveとrejectは自分で書き換えることができます.もちろん直してから正常な流れがいけなくなりました.
    私達の最終バージョンはこのようです.
    function helloPromise(cb) {
      this.resolve = this.resolve.bind(this);
      this.reject = this.reject.bind(this);
      this.catch = this.catch.bind(this);
      this.then = this.then.bind(this);
    
      this._promiseStatus = 'pending';
      try{
        cb(this.resolve, this.reject);
      }catch(e){
        this._promiseValue = e;
      }
      
      return {then: this.then, catch: this.catch};
    }
    
    helloPromise.prototype.then = function (cb){
      if(toString.call(this._promiseValue) === '[object Error]'){
        return this;
      }
      if(this._promiseStatus === 'fulfilled'){
        try{
          this._promiseValue = cb(this._promiseValue);
        }catch(e){
          this._promiseValue = e;
        }
      }
      return this;
    }
    
    helloPromise.prototype.catch = function (cb){
      if(toString.call(this._promiseValue) === '[object Error]'){
        try{
          this._promiseValue = cb(this._promiseValue);
        }catch(e){
          this._promiseValue = e;
        }
        return this;
      }
      if(this._promiseStatus === 'rejected'){
        try{
          this._promiseValue = cb(this._promiseValue);
        }catch(e){
          this._promiseValue = e;
        }
      }
      return this;
    }
    
    helloPromise.prototype.resolve = function (arg){
      if(this._promiseStatus === 'pending'){
        this._promiseStatus = 'fulfilled';
        this._promiseValue = arg;
      }
    }
    
    helloPromise.prototype.reject = function (arg){
      if(this._promiseStatus === 'pending'){
        this._promiseStatus = 'rejected';
        this._promiseValue = arg;
      }
    }
    
    卵はあまり使いません
    =================を見て、このコードに問題があると言って、テスト用のサンプルを提供しました.瞬間的に顔を打つというのは、同期の論理が書かれています.thenとcatchが先に実行されます.setTimeoutがresoliveを実行する時に、thenとcatchが全部実行されました.コンストラクションでリガのcalback配列ができます.thenとcatchは全部calbackの中にpushします.でもここでは書きません.規範を見てから問題が多すぎます.
    let pp= new Promise((resolve, reject) => {
    	setTimeout(()=>{
    		resolve('done')
    	},100);
    });
    
    pp.then((value) => {
    	console.log(value);
    }).catch((e)=>{
        console.log(e);
    });