非同期実行の簡単な例
以下の例では2つのブロックが非同期に実行され、コードが書かれた順番ではなく実行時間の短い順に出力される。
1 2 3 4 5 6 7 8 9 10 |
setTimeout(() => { console.log('Long execution'); }, 300); setTimeout(() => { console.log('Short execution'); }, 100); // 100ms execution // 300ms execution |
Promiseによる実行順序の保証
基本形
Promiseオブジェクト.then()
この基本形では、以下の手順で処理間を同期させる。
Promise
オブジェクト生成- 生成時の引数で渡す無名関数に先行処理を記述
- 無名関数の引数で処理終了を発行する関数(
resolve
)を受け取り - 先行処理終了のところで
resolve
関数を実行
Promise
オブジェクトのthen
メソッドを記述then
メソッドの引数で渡す無名処理に後続処理を記述- この後続処理は、先行処理の
resolve
関数が実行された後に実行される
1 2 3 4 5 6 7 8 |
p = new Promise(resolve => { 先行処理 resolve(); }); p.then(() => { 後続処理 }); |
処理完了のための関数名は任意だが、staticメソッドと同じ関数名のresolve
が使われる。
以下の例では、Promise・・・・・・・・・・・・・無名関数の引数をresolve
として受け取り、resolve
関数を300ms待機後の表示の後に実行している。
そしてその実行後に100ms待機の処理が実行される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
let p = new Promise(resolve => { setTimeout(() => { console.log('300ms execution'); resolve(); }, 300); }); p.then(() => { setTimeout(() => { console.log('100ms execution'); }, 100); }); // 300ms execution // 100ms execution |
Promise
オブジェクトのthen
メソッドには引数に無名関数を指定する。Promise
オブジェクトで設定したresolve
メソッドが実行された後に引数の無名関数が実行される。
以下の例では、上のPromise
オブジェクトで設定した300ms待機後の表示の後に、then
メソッドで設定した100ms待機・表示が実行される。
1 2 3 4 5 6 7 8 9 |
// Promise.thenメソッドの無名関数に待機後処理を記述 promise.then(() => { setTimeout(() => { console.log('100ms execution'); }, 100); }); // 300ms execution // 100ms execution |
new Promise~then
生成したPromise
オブジェクトから直接then
メソッドを実行してもよい。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
new Promise(resolve => { setTimeout(() => { console.log('300ms execution'); resolve(); }, 300); }).then(() => { setTimeout(() => { console.log('100ms execution'); }, 100); }); // 300ms execution // 100ms execution |
Promiseオブジェクトを返す
優先実行させたい処理をPromise
オブジェクトとして、そのインスタンスを関数の戻り値とする書き方。関数にthen
メソッドが適用できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// 関数の戻り値をPromiseとする例 function doFirst() { // 優先実行させたい関数をPromiseでラップ p = new Promise(resolve => { setTimeout(() => { console.log('300ms execution'); resolve(); }, 300); }); // Promiseオブジェクトを返す return p; } // 戻り値のPromiseオブジェクトに対してthenを実行 doFirst().then(() => { setTimeout(() => { console.log('100ms executiohn'); }, 100); }); // 300ms execution // 100ms executiohn |
resolveで値を渡す
resolve
関数に引数を渡し、これをthen
メソッドで受け取ることができる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// resolve実行時に引数を渡す例 const promise = new Promise(resolve => { setTimeout(() => { console.log('300ms execution'); // resolve実行時に引数を渡す resolve('Resolved!'); }, 300); }); // thenの無名関数の引数で3resolveに渡された引数を受け取る promise.then(parameter => { // 受け取った引数を利用 console.log(parameter); setTimeout(() => { console.log('100ms execution'); }, 100); }); // 300ms execution // Resolved! // 100ms execution |
thenのチェイン
then
メソッドを連ねてシリアルに実行させる書き方。後続を持つthen
メソッドの戻り値をPromise
オブジェクトとするのがミソ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
new Promise(resolve => { setTimeout(() => { console.log('300ms execution'); resolve('Promise executed'); }, 300); // 1つ目のthen }).then(() => { // thenメソッドでPromiseオブジェクトを返す return new Promise(resolve => { setTimeout(() => { console.log('200ms execution'); resolve('First then method executed'); }, 200); }); }).then(() => { // 最後のthenではPromise~resolveは不要 setTimeout(() => { console.log('100ms execution'); }, 100); }); |
reject
Promise
の処理で何らかの問題が生じた場合にrejectすることができる。この場合、resolve
が実行されないのでthen
は処理されず、直近のcatch
が呼ばれる。
以下の例ではPromise
オブジェクトで300msのブロックの最後でreject
が実行され、then
メソッドは実行されずにcatch
メソッドが実行される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// 無名関数の2つ目の引数でreject関数を受け取る promise = new Promise((resolve, reject) => { setTimeout(() => { console.log('300ms execution'); // reject関数を実行 reject('Rejected!'); }, 300); }) // 正常にresolveされた場合 promise.then(() => { setTimeout(() => { console.log('100ms execution'); }, 100); // rejectされた場合 }).catch(err => console.log(err)); // 300ms execution // Rejected! |
Promise.all~全ての実行を待機
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { console.log('Took 100ms'); resolve('value 1'); }, 100); }); const promise2 = new Promise((resolve, reject) => { setTimeout(() => { console.log('Took 200ms'); resolve('value 3'); }, 200); }); const promise3 = new Promise((resolve, reject) => { setTimeout(() => { console.log('Took 300ms'); resolve('value 2'); }, 300); }); // 3つのPromiseオブジェクトの実行を待ってからthenを実行。 Promise.all([promise1, promise2, promise3]).then((values) => { console.log('All completed.'); // resolveに渡された引数は配列として渡される。 console.log(values); }); // Took 100ms // Took 200ms // Took 300ms // All completed. // Array(3) // 0: "value 1" // 1: "value 3" // 2: "value 2" // length: 3 |