LANG SELRCT

コードを書く場所

2019年2月24日日曜日

JavaScriptでPromiseの処理を試みる


Google Apps ScriptのHtmlServiceでPromiseの処理を試みた備忘録。



[プロローグ]
時間のかかる処理がある時に、その処理が終わってから次の処理を実行したい。
でもJavaScriptは非同期処理で、実行した処理が終わるまで待ってはくれないため、意図した順番通りに実行して値を渡したいときには工夫が必要。

その工夫として、かつてはコールバック関数を重ねていたが、可読性が良くなかった。
その可読性の問題を解決するためにPromiseの処理が考え出された。

と理解しています。

FYI


[個人的な体験]
Promiseの処理は個人的に理解に苦しみました。(まだ理解しきれてはいない)
いくつか書き方を変えて書いてみてなんとなくわかってきた備忘録として、以下にコードを残しました。

言葉で説明しようとするとどんどんわかりにくくなるので、コードを書いて動きを確認しながら、別の書き方で書き直してみてちょっとわかった気になれた。


まずは調べた時によく見る書き方(index.htmlのPromise以下のコード)

コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する



参考にしたサイトではsetTimeoutで時間のかかる処理を作っていましたが、ここではログを出すだけにします。

index.html
<!DOCTYPE html>
<html lang="ja"> 
  <body>
    <script>
/************************************
Promise
/************************************/
myPromise1();
function myPromise1() {
  var promise = new Promise(function (resolve, reject) {
    console.log(1);
    resolve();
  });

  promise.then(function() {
      console.log('2 エラーを投げる');
      throw new Error("エラーメッセージ");
    })
    .catch(function(error) {
      console.log("3 " + error);
    })
    .then(function() {
      console.log(4);
    });
}

  </script>
</body>
</html>


次に上の書き方を、いろいろ書き換えてみる

どのボタンを押しても同じように処理が実行されてconsole.logに順番に結果が出る




コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html lang="ja"> 
  <body>
  <button id="myPromise1">myPromise1</button>
  <button id="myPromise2">myPromise2</button>
  <button id="myPromise1_2">myPromise1_2</button>
  <button id="myPromise2_2">myPromise2_2</button>
    <script>
/************************************
イベント
/************************************/
elem('myPromise1').onclick = myPromise1;
elem('myPromise2').onclick = myPromise2;
elem('myPromise1_2').onclick = myPromise1_2;
elem('myPromise2_2').onclick = myPromise2_2;

function elem(id) {
  return document.getElementById(id);
}

/************************************
myPromise1上のコードと同じもの
/************************************/
function myPromise1() {
  var promise = new Promise(function (resolve, reject) {
    console.log(1);
    resolve();
  });

  promise.then(function() {
      console.log('2 エラーを投げる');
      throw new Error("エラーメッセージ");
    })
    .catch(function(error) {
      console.log("3 " + error);
    })
    .then(function() {
      console.log(4);
    });
}

/************************************
myPromise2
myPromise1をPromise.resolve(funcB())で書き換える
/************************************/
function myPromise2() {
  var promise = Promise.resolve(funcB());
  promise.then(funcA)
  .catch(erroeFunc)
  .then(funcC);
}

/************************************
myPromise1_2
myPromise1をnew Promise(promiseFunc)で書き換える
var promiseという変数を作らない
/************************************/
function myPromise1_2() {
  new Promise(promiseFunc)
  .then(funcA)
  .catch(erroeFunc)
  .then(funcC);
}

function promiseFunc(resolve, reject) {
  funcB();
  resolve();
}

/************************************
myPromise2_2
myPromise2をPromise.resolve(funcB())で書き換える
var promiseという変数を作らない
/************************************/
function myPromise2_2() {
  Promise.resolve(funcB())
  .then(funcA)
  .catch(erroeFunc)
  .then(funcC);
}

/************************************
処理
/************************************/
function funcA() {
  console.log('2 エラーを投げる');
  throw new Error("エラーメッセージ");
}

function funcB() {
  console.log(1);
}

function funcC() {
  console.log(4);
}

function erroeFunc(error) {
  console.log("3 " + error);
}

  </script>
</body>
</html>



実行結果

デベロッパーツールのConsoleに順番にログが出ます。