Open7

javascriptの非同期処理(Promise)

bigbigcatatmospherebigbigcatatmosphere

Promiseとは

  • ECMAScript2015で追加された組み込みのクラス、非同期処理を実現する
  • Futureパターンを実装したもの。
  • callbackにあった以下の問題を解決する
    • ネストが深くなる
    • 標準化されていないcallback関数の取り扱いの負荷
    • エラー処理
    • 複数の非同期処理の可読性が下がる
bigbigcatatmospherebigbigcatatmosphere

Promiseが解決する問題

1. ネストが深くなる

callback関数は以下のように記述する


import { readFile } from "fs";

readFile("hoge.txt", (err, data) => {
    if (err) {
        console.error("An error occurred.");
        return;
    }
    
    readFile(data.toString(), (err, data) => {
        if (err) {
            console.error("An error occurred.");
            return;
        }
        
        readFile(data.toString(), (err, data) => {
            if (err) {
                console.error("An error occurred.");
                return;
            }
            
            console.log(data.toString());
        });
    });
})

こういった感じで、callback関数が取得する結果を下に別のcallbackを行いたい場合、callback関数の中に、新たなcallback処理を追加していく必要がある。

bigbigcatatmospherebigbigcatatmosphere

2. 標準化されていない標準化されていないインターフェース

callback処理は各環境に合わせたAPIで提供されており、開発者は都度取り扱いを把握必要がある

setInterval(() => {
  console.log('hello');
}, 1000);

import { readFile } from "fs";

readFile("hoge.txt", (err, data) => {
  console.log(data);
}
bigbigcatatmospherebigbigcatatmosphere

3. エラー処理の見通し

以下の様には書けない。
非同期処理で発生した例外の補足を呼び出し元の同期処理で行うのが難しい

import { readFile } from "fs"
try {
    readFile("data.txt", (err, data) => {
        if (err) {
            throw err
        }
    })
} catch (e) {
  console.log(e) // ここで例外を補足できない
}
bigbigcatatmospherebigbigcatatmosphere

4. 複数の非同期処理の可読性が下がる

asyncProc1()
asyncProc2()
asyncProc3()
asyncProc4()

とか書きたいだけのところをコールバックをネストしなければいけない

bigbigcatatmospherebigbigcatatmosphere

Promiseオブジェクト

  • 非同期処理関数はPromiseオブジェクトを返すように実装されている(Promiseでラップされている)
  • Promiseオブジェクトは3つの状態をもち、初期状態から、一度だけ状態変化する
    • 初期状態: pending
    • 成功: fullfilled
    • 失敗: rejected
  • Promiseオブジェクトの生成においては
    • コンストラクタにコールバック関数を引数として渡す
    • 対象のコールバック関数には、reslove, reject関数を引数として渡す
    • コールバック関数内部の処理が以下の条件を満たすようにする
      • 正常に終了した場合、reslove関数を呼び出す
      • 異常に終了した場合、reject関数を呼び出す
    • コールバック関数内で例外が発生した場合は、Promiseオブジェクトがrejectで補足してくれる
bigbigcatatmospherebigbigcatatmosphere
  • Promiseオブジェクトの取り扱い
    • 同期処理ではまだ状態がpendingのPromiseオブジェクトが返却される
    • 値が確定した場合、then, catch, finallyのコールバック関数が処理され結果を取り出せる
  • then関数の仕組み
    • 非同期処理の成功時、失敗時ように引数を2つとる事ができる
      • 第一引数: 成功時の処理を記載する
        • 引数が関数でない場合、そのまま値を返す関数(Indentity function)が渡る
      • 第二引数: 失敗時の処理を記載する
    • thenはPromiseオブジェクトを返す
      • thenに渡したコールバック関数がPromiseオブジェクトを返せばそのままそれを返す
      • それ以外の場合(引数が関数出ない場合)は、Promiseでラップして返す
        • return Promise.resolve(関数値)なイメージ
      • thenに渡したコールバック関数が例外を発生したら、失敗値をラップしたPromiseオブジェクトを返す
  • catch関数の仕組み
    • thenとほぼ同じ、引数が1つだけになり、失敗時の処理を値 or コールバック関数として渡す

    • ただし、then,catchにはcallbackを渡すことしか無いと思うので、値も渡せる程度に考えておけばいい

    • then, catchに渡したコールバック関数の結果がPromiseであることを覚えておけばいい

        const huga: Promise<number> = Promise.resolve(10).then((data) => {
 return data;
});