IT関連のメモ

メモです

JavaScriptのPromiseについて

身内向け 口頭説明含むこと前提

JavaScriptのPromiseがとっつきにくい気がしたのでまとめます。

概要

JavaScript、TypeScript
世の中、利用多い

www.itmedia.co.jp

だから使う機会もあるだろうし、ここではとっつきにくそうなPromiseについて触れる

function promiseTest(): Promise {
  return new Promise(async (resolve) => {
    resolve();
  });
}

promiseTest().then(async () => {
  promiseTest().then(async () => {
    console.log(`promiseTest1.`);
  });
  promiseTest().then(async () => {
    console.log(`promiseTest2.`);
  });
  promiseTest().then(async () => {
    console.log(`promiseTest3.`);
  });
});

Promise

JavaScriptはシングルスレッドだけど、フロントやってたら非同期の処理は欲しい
JavaScriptのPromiseはJavaScriptだけどマルチスレッドというか非同期の処理をしたいときに使うもの
C#のTask、JavaのThread的に使える

resolve reject

サクセスコールバック、エラーコルバック
成功時のデリゲート、失敗時のデリゲート

扱いが微妙にフレームワークで異なる気がする

function promiseTest(resolve, reject){
    resolve();
    reject();
}

promiseTest(() => {
    console.log(`success`);
},
() => {
    console.log(`failure`);
});

※イメージの説明 Promise使ってすらいない例

このように明示的にサクセスコールバック、エラーコルバックの実行を指定できる。
この例ではサクセスコールバック、エラーコルバックを両方実行しているおバカなコードであるがこういうことができるという説明。
普通は↓みたいになるかと思う

https://jsfiddle.net/Jirobe/1dw5g9fh/27/

const isSuccess = true;

function promiseTest(resolve, reject){
  // 何らかの成功・失敗の共通ロジック
  // 何らかの判断ロジック
  if(isSuccess){
    // 何らかの前処理
    resolve();
    // 何らかの後処理
  }else{
    // 何らかの前処理
    reject();
    // 何らかの後処理
  }
}

promiseTest(() => {
    console.log(`success`);
},
() => {
    console.log(`failure`);
});

※イメージの説明 Promise使ってすらいない例

これはいい。引数にあるからみんな読める。thenが扱いにくい

then

thenがresolve、catchがreject

これはわかってもらえると思う
関数使ってPromisを5個作ってる

https://jsfiddle.net/Jirobe/1dw5g9fh/39/

let count = 0;

function promiseTest(): Promise {
    console.log(++count);
  return new Promise((resolve) => {
    resolve();
  });
}

promiseTest().then( () => {
  promiseTest().then( () => {
    promiseTest().then( () => {
      promiseTest().then( () => {
        promiseTest().then( () => {
          console.log(`last:` + count);
        });
      });
    });
  });
});

then これがきつい。意味は全然違うけど、↑と↓は出力が同じもの

https://jsfiddle.net/Jirobe/1dw5g9fh/45/

let count = 0;

function promiseTest(): Promise {
    console.log(++count);
  return new Promise((resolve) => {
    resolve();
  });
}

promiseTest()
.then( () => { 
    console.log(++count);})
.then( () => { 
    console.log(++count);})
.then( () => { 
    console.log(++count);})
.then( () => { 
    console.log(++count);})
.then( () =>  {console.log(`last:` + count);})

Promisを一度作ればthenでいくらでもつなげられる。成功したら、次に行く。
これは同じ処理を連続してよんでいるけど、仕事で人が作る現実のプログラムは別々の意味のある処理がかかれているわけで、大きいソースのプロジェクトでこれが混ざってくるとコールバックが別の場所に書いてあったりで頭が爆発するからそういうものだと覚悟がいる。

シグナルやメッセージを指定してデリゲート仕掛けるタイプのemitとかsubscribeとかの単語を使いそうなメッセージ系のイベント管理と違って、必ず前後関係を間違えずに順番に処理してくれるのでビジネスでは安心かもしれない。マルチスレッドだけど、並列になることはない。一つのワーカースレッドで大きい処理をしている感覚。

catch

catchがreject

https://jsfiddle.net/Jirobe/1dw5g9fh/51/

let count = 0;

function promiseTest(): Promise {
    console.log(++count);
  return new Promise((resolve, reject) => {
    if(count > 0){reject();}
  
    resolve();
  });
}

promiseTest()
.then( () => { 
    console.log(++count);})
.then( () => { 
    console.log(++count);})
.then( () => { 
    console.log(++count);})
.then( () => { 
    console.log(++count);})
.then( () =>  {console.log(`last:` + count);})
.catch(() => {console.log(`failure`);});

止まる。

でも、この場合、こうだと止まらない。if文のチャンスは最初の一回だけだから

let count = 0;

function promiseTest(): Promise {
    console.log(++count);
  return new Promise((resolve, reject) => {
    if(count > 1){reject();}
  
    resolve();
  });
}

promiseTest()
.then( () => { 
    console.log(++count);})
.then( () => { 
    console.log(++count);})
.then( () => { 
    console.log(++count);})
.then( () => { 
    console.log(++count);})
.then( () =>  {console.log(`last:` + count);})
.catch(() => {console.log(`failure`);});

なのでこう書かないといけない

https://jsfiddle.net/Jirobe/1dw5g9fh/62/

let count = 0;

function promiseTest(): Promise {
    console.log(++count);
  return new Promise((resolve, reject) => {
    if(count > 1){reject();}
  
    resolve();
  });
}

promiseTest()
.then( () => { 

  promiseTest()
  .then( () => { 
      promiseTest()
    .then( () => { 

        promiseTest()
      .then( () => { 

            promiseTest()
          .then( () => { 

              console.log(`last:` + count);
            ;}
          ).catch(() => {console.log(`failure`);});
        ;}
      ).catch(() => {console.log(`failure`);});
      ;}
    ).catch(() => {console.log(`failure`);});

    ;}
  ).catch(() => {console.log(`failure`);});
  
  ;}
).catch(() => {console.log(`failure`);});
 

あと、catch句の通り、例外の時も実行される
finallyもある

https://jsfiddle.net/Jirobe/1dw5g9fh/75/

let count = 0;

function promiseTest(): Promise {
    console.log(++count);
  return new Promise((resolve, reject) => {
  
    if(count > 1){reject();}
    resolve();
  });
}

promiseTest()
.then( () => { 
    console.log(++count);   
  if(count > 1){throw new Error();}
  },() => {console.log(`failure`))
.then( () => { 
    console.log(++count);   
  if(count > 1){throw new Error();}
  },() => {console.log(`failure`))
.then( () => { 
    console.log(++count);   
  if(count > 1){throw new Error();}
  },() => {console.log(`failure`))
.then( () => { 
    console.log(++count);   
  if(count > 1){throw new Error();}
  },() => {console.log(`failure`))
.then( () =>  {console.log(`last:` + count);},() => {console.log(`failure`);})
.finally(() => {console.log(`finally`);});