ES6 Promise

基本

※まずはPromiseを返す関数を使用を前提

then の中に成功時・失敗時の関数を持つ

axios.get('hoge.json')
    .then(
        response => {
            // 成功時の処理 response.data にレスポンスが格納
            console.log(response);
        },
        reason => {
            // 失敗時の処理
            console.log(reason);
        }
    );

もしくは、 thenには成功時の関数だけを持ち、失敗時は catch で受ける(Promiseチェーンを考えるとこちらの型の方がよく使う?

axios.get('test2.json')
    .then(
        response => {
            // handle success
            console.log(response);
        }
    )
    .catch(function (error) {
        console.log(error);
    });

Promise チェーン

doSomething()
    .then(
        response => {
            console.log('1つめ');
            return doSomething2(response);
        }
    )
    .then(
        response => {
            doSomething3(response)
        }
    )
   .then(
        response => {
            console.log('最終的に'+response)
        }
    )
    .catch(function (error) {
        console.log('どこかで失敗した場合はこのルート');
    });
    // ; で終わらせず、catchの後にthen をつなげることもできる

Promiseの静的メソッド

Promise.all(配列)

すべてのプロミスが解決されるか、拒否されるかするまで待つ
すべてのプロミスは並行して実行される。(逆にいうと直列実行される必要がある場合はチェーンする必要がある)
values は、プロミスが渡された順になる。

Promise.all([doSometihg1, doSometihg2, doSometihg3])
    .then((values) => {
        console.log(values);
    }
);

Promise.resolve(value)

与えられた値で解決された新しい Promise オブジェクトを返す。
#逐次実行をする直列的な合成については後日調べてまとめる

//以下2つ同じ意味
const hoge = new Promise(resolve => {
    resolve();
});
const hoge = Promise.resolve();

Promise.reject(reason)

与えられた理由で拒否された新しい Promise オブジェクトを返す。

//以下2つ同じ意味
const hoge = new Promise((resolve, reject) => {
    reject(new Error("エラー"));
});
const hoge = Promise.reject(new Error("エラー"));

Promiseのインスタンスメソッド

then と catch 以外には finally がある。
finally は元のプロミスが解決されたときに解決される新しいプロミスを返す。
#使いどころは後日調べてまとめる

Promiseの作成

非同期なのにPromiseをかえさない関数はPromise関数をつかってラップする

const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('foo');  // 成功したときに渡す値
    }, 300);
    // setTimeout だと失敗がないのでこの例では書けないけど、
    // 失敗したときは reject('失敗した理由')
});

setTimout を 汎用的な wait 関数にする

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

wait(10*1000).then(() => saySomething("10 seconds"));

async / await ※ES8

非同期関数(async function)宣言

async function aaa() {
    // ...
}
// もしくは アロー関数もOK
async () => {
    // ...
}

結果はPromise となる(return した値で resolve、throw した場合はその値で reject)

// 以下は同じ結果になる
async function hoge() {
    return 1; // promise にラップされる
}
function hoge() {
    return Promise.resolve(1);
}

非同期関数は、await 式を含むことができる(次の項)

await 式

await 式は async function の実行を一時停止し、Promise の解決または拒否を待つ

【解決された promise の値】 = await 【解決を待つPromise】;

非同期関数内でawait を使用する

async function hoge() {
    try {
        // try は複数awaitをラップできる。エラーができたところでcatchブロックに飛ぶ
        let res1 = await fetch('https://hoge.com/hoge1'); 
        let res2 = await fetch('https://hoge.com/hoge2');
    } catch(err) {
        // Promise がrejectされたときにひろう catch が必要
        alert(err); // TypeError: failed to fetch
    }
}

並行で処理したい場合は Promise.all でラップする

async function hoge() {
    try {
        let res_all = await Promise.all([
            fetch('https://hoge.com/hoge1'),
            fetch('https://hoge.com/hoge2')
        ]);
    } catch(err) {
        alert(err); // TypeError: failed to fetch
    }
}

throw と Error

throw

throw  はユーザ定義の例外を発生させ、catch ブロックに飛ぶ。
catch がなければそこでプログラムを終了させる

function hoge(obj) {
    if(!obj){
        throw 'Errorだよ';
    }
}
try {
    hoge();
} catch (e) {
    console.error(e); // 'Errorだよ'
}

// 非同期のthrowはそのままではcatchできないので、
// ↑のほうで書いたPromiseを使ってcatchする
function hoge2() {
    setTimeout(()=>{
        throw 'Errorだよ';
    },2000);
}
try {
    hoge2();
} catch (e) {
    console.error(e); // ここにはこない
}

Error

throw は文字列をなげるのではなく、Errorオブジェクトを生成して渡す

throw new Error('エラーだよ');

Error(一般的なエラー) 以外に以下のようなErrorコンストラクタがあるので適宜使い分ける

TypeError 変数または引数の型が有効でない
SyntaxError 構文エラー
URIError URIが正しくない

Errorオブジェクトだと、filename(エラーが発生したファイルのパス)やname(Errorの種類で変わる)などが確認できる