😎

パイプラインPromise入門

2022/09/22に公開

突然ですが皆さんはこんなコードを書いていたりしませんか?

const result= fun3(func2(await func1()))

この書き方だとどの関数がどの引数をとっているか見ずらいですが、各関数の結果ごとに変数に代入したりするのも面倒くさいですよね!

そんな時にPromiseを使うとこのように書けます

const result = await func1().then(func2).then(func3)

これだと結構見やすくないですか?そう、見やすいんです。
このようにPromiseをパイプラインとして使うことでコードの可読性を上げることができます。

また、この方法を使うとエラーハンドリングも簡単になることがあります。
例えば以下のようなコードがあったとします。

try{
  const result= fun3(func2(await func1()))
}catch(e){
  console.error(e)
}

それを先ほどの手法で書き換えるとこうなります

const result = await func1().then(func2).then(func3).catch(console.error)

かなり見やすく、すっきりしたことがわかると思います

ここまでのテクニックは既に使っている方がいるかもしれません。
では、以下のパターンはどうでしょうか?

const result = func3(func2(func1()))

そう!このままでは起点となるfunc1がPromiseを返さないので、パイプラインを始めることができません。
それでも意地でもパイプラインな書き方をしたいのであれば、以下のような書き方をすることができます。

const result = Promise.resolve(func1()).then(func2).then(func3)

こうすればPromiseパイプラインを使えますし、先ほどのエラーハンドリングもできます。

まだまだ行きます。さらに以下のパターンどうすればうまくパイプラインを使えるでしょうか

const result= fun4(func3(),func2(await func1()))

無茶苦茶見ずらいですがfunc4が二つの引数をとっていることがわかります。
これをパイプライン化するとこうなります

const result = await func1()
  .then(func2)
  .then((value) => func4(func3(),value));

すこし改善されましたが、まだ見ずらいです。そこで、curryという関数を作成します。

const curry =
  <T, U, E>(func: (arg1: T, arg2: U) => E) =>
  (a: T) =>
  (b: U) =>
    func(a, b);

そしてこのcurryを使うと以下のように書けます。

const result = await func1().then(func2).then(curry(func4)(func3()));

すばらしい!!

そして最後に以下の場合をパイプライン化してみましょう。

const result = fun4(await func3(), func2(await func1()));

今のcurry関数ではfunc3が返したPromiseをうまく処理できません。
なので、curry関数を以下のように書き換えます。

const curry2 =
  <T, U, E>(func: (arg1: T, arg2: U) => E) =>
  (a: T | Promise<T>) =>
  (b: U | Promise<U>) =>
    Promise.all([a, b]).then(([a, b]) => func(a, b));

そしてこれを使うと....

const result = await func1().then(func2).then(curry2(func4)(func3()));

😎😎 Perfect 😎😎

今回はここまでにしておきます。よきPromiseライフを!!

Discussion