LoginSignup
1
0

More than 5 years have passed since last update.

Promiseでfinallyっぽいことをする

Last updated at Posted at 2017-09-15

概要

Promiseでfinallyっぽいことをしたい。

でも、Promiseは、finallyと異なり、データやエラーが渡されるので、前の処理から渡された結果を、どうするのか、次の処理に何を渡すのか、エラーをどうするのかによって、finallyっぽいものの実装方法が何種類も考えられます。

さて、何らかのリソースをクローズしたり一時ファイルを削除するような処理の場合、クローズの結果そのものは、次の処理に渡す必要はなく、クローズの前のデータを次の処理に渡したいことが多いと思います。つまり、「前の処理の内容を、透過的に次の処理に渡す」、データの流れ的には一切手を付けず、finallyっぽい処理をすれば、使い勝手が良さそうです。

そこで、こんなコードを書いてみました。

コード

Promise.prototype.finally = function (promisable) {
    return this.then(
        function (originalResult) {
            return Promise.resolve(promisable())
                .then(function(result) {
                    return originalResult;
                })
        },
        function (originalReason) {
            return Promise.resolve(promisable())
                .then(
                    function (result) {
                        return Promise.reject(originalReason);
                    },
                    function (reason) {
                        reason.parent = originalReason;
                        return Promise.reject(reason);
                    }                
                )
        }
    )
}

使用例

doSomething(file)
  .finally(()=>{
     fs.unlink(file);
  })
 .then((result)=>{
      // finallyは無視して、doSomethingの結果を受け取る
  })
 .catch((cause)=>{
    // finallyを含めた、すべてのエラーを受け取る。二重にエラーだった場合は、parentに前のエラーを保持。
  })

補足

やっぱり、originalReason(「処理」の結果)を受け取りたいと考える人もいるかもしれませんが、その場合は、エラーとの分岐が必要で、それなら、普通にthenを書いて、受け取った結果を次に渡せば良いわけです。分岐が必要ないからこそ、一つの処理として書きたい。なので、ほとんどの場合、この実装で問題ないのではないかと思います。

問題

そもそも、Promiseの実装が多数あって、特定のライブラリが返すpromiseが、グローバルのPromiseのインスタンスではないことが多々あります。で、そういう場合には、Promise.resolve()してやらないといけない。これは、あまりエレガントではありません。

ついでに言うと、標準でもなんでもない拡張を、Promiseに加えるのは、品質管理的にあまり良くありません。ですので、これはあくまで実験的な機能として、頭の隅に置いておいてもらえればと思います。

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0