ウェブエンジニア珍道中

日々の技術的に関する経験を書いていきます。脱線もしますが助けになれば幸いです。

TypescriptでPromiseについてまとめてみる

わかった気がせんでもないのでまとめます。

async/awaitを勉強しようとしたら「そもそもPromiseが分からんと話にならん」ということで勉強しました。

今更感&検索したらいっぱい出てきますが自分の理解が進むから良いんです(自分本位)

Promiseとは

ECMAScript 2015(ECMAScript 6)で新しく追加された機能で、これを使うと非同期をいい感じに記述できるもの(らしい)です。

コールバック地獄とかあるらしいですが、ここでは省略。

導入してみる

tsconfig.jsonのオプションでtargetes6にしておきます。(es5やesnextでも可)

{
  "compilerOptions": {
    "target": "es6"
  }
}

そして型定義ファイルを取り込みます。

npm install @types/es6-promise

これで準備ができました。

サンプル

簡単なサンプルを書いてみます。

const anyProcessing = (): boolean => {
    // 何かの処理を行っていると仮定、5割の確率でコケる(falseを返す)
    return Math.random() >= 0.5;
}

const test_promise = new Promise(
    (resolve: () => void, reject: () => void) => {
        if(anyProcessing()) {
            resolve();
        }
        reject();
    }
)

test_promise.then(() => {
    console.log("処理に成功しました");
}).catch(() => {
    console.log("処理に失敗しました");
});

Promiseは最大2つの関数を引数として受け取る関数を渡して生成します。

引数に渡している部分を抜き出すとこんな感じです。

(resolve: () => void, reject: () => void) => {
    if(anyProcessing()) {
        resolve();
    }
    reject();
}

resolverejectが仮引数になっています。何かしらの処理(ここではanyProcessingメソッド)を実行し、成功した時にはresolve, その後rejectを呼び出しています。

Promissオブジェクトは成功・棄却・未解決の3つの状態を持っていて、reject()およびresolve()は未解決状態じゃないと実行されないようです。なのでif文の箇所はelseでなくても意図通りの挙動になっています。

そして、生成したpromissオブジェクトからthencatchメソッドを呼び出し、成功した場合と失敗した場合の処理を記述します。

この2つのメソッドもそれぞれ関数を受け取り、ここで渡した関数がpromissオブジェクト生成の際のコンストラクタに渡した仮引数に入っていきます。今回の場合はthenの処理がresolveに, catchに入れた処理がrejectに入ります。

実行結果はこんな感じ。

$ ts-node promiseTest.ts
処理に成功しました # 毎回1/2の確率で変わる

非同期っぽくする

非同期にしていることがわかるような処理にしてみます。

const anyProcessing = (): boolean => {
    for(let i_ = 1; i_ < 1000000; i_ *= 1.0000001)  { /* テキトーな時間潰す処理 */ }
    return Math.random() >= 0.5;
}

const test_promise = new Promise(
    (resolve: () => void, reject: () => void) => {
        if(anyProcessing()) resolve();
        reject();
    }
)

test_promise.then(() => {
    console.log("処理に成功しました");
}).catch(() => {
    console.log("処理に失敗しました");
});

console.log("後ろに書いた別の処理を実行したよ");

実行結果

$ ts-node "myPromise.ts"
後ろに書いた別の処理を実行したよ
処理に失敗しました

先に後ろに書いた別の処理が実行されました。非同期を割と手軽に書くことが出来ました。

RxJSも便利ですが、こっちはこっちで手軽だと思いました(関数を渡す関数辺りで混乱しまくったけど)。

thencatchの箇所をもう少し手軽に書くためにasync/awaitがあるようなので追って勉強していきたいと思います。では。