非同期処理を行う
非同期処理を行うには、Promise
オブジェクトを使用します。
Promiseオブジェクトはnew
を使用して実行します。
- ※ IEはすべてのバージョンで対応していません。
構文
var promise = new Promise(functionExecute);
引数名 | 型 | 説明 | |
---|---|---|---|
第一引数 | functionExecute | Function | 非同期処理をする関数 |
functionExecuteの引数
new Promise(function(functionResolve, functioReject) { ... });
引数名 | 型 | 説明 | |
---|---|---|---|
第一引数 | functionResolve | Function | 解決した時に実行する関数 |
第二引数 | functioReject | Function | 拒否した時に実行する関数 |
戻り値
Promiseオブジェクトを返します。
サンプルコード
JavaScript
new Promise(function(resolve) {
setTimeout(function() {
resolve();
}, 2000);
});
非同期処理をする関数には2つの引数が含まれています。
第一引数の関数は解決した時に実行し、第二引数は拒否した時に実行します。
メソッド
Promiseはいくつかのメソッドを持っています。
メソッド名 | 説明 |
---|---|
then | 解決した時の関数(構文で説明したfunctionResolve)を実行した際に実行されるコールバック関数 |
catch | 拒否した時の関数(構文で説明したfunctioReject)を実行した際に実行されるコールバック関数 |
finally | 一番最後に実行されるコールバック関数 |
all | 複数のPromiseを実行しその結果に応じて解決または拒否する 解決は指定した複数のPromise全てが解決された時のみ |
race | 複数のPromiseを実行しその結果に応じて解決または拒否する 複数のPromiseの何れか1つが解決または拒否で処理される |
非同期処理をする関数(構文で説明したfunctionResolveとfunctioReject)にはそれぞれ引数で値を渡すことができ、渡した値はthenやcatchメソッドで受け取ることができます。
ただし、渡すことのできる引数の指定は1つだけです。
次のサンプルコードでは2秒後にランダムで1か2を返し、1ならresolve、2ならrejectを実行します。
さらに1ならコンソールでOKが表示され、2ならコンソールでNGが表示され、最後にコンソールでFinishが表示されます。
JavaScript
new Promise(function(resolve, reject) {
setTimeout(function() {
var num = Math.floor(Math.random() * (2 + 1 - 1) + 1);
if (num === 1) {
resolve('OK');
} else {
reject('NG');
}
}, 2000);
}).then(function(message) {
console.log('解決', message);
}).catch(function(data) {
console.log('拒否', message);
}).finally(function() {
console.log('Finish');
});
thenメソッドはチェーンメソッドとして繋ぐことができます。
また、thenメソッド内でreturn
で値を返すと次のthenメソッドに引数としてその値を渡すことができます。
JavaScript
new Promise(function(resolve) {
setTimeout(function() {
resolve('OK');
}, 2000);
}).then(function(message) {
console.log('解決', message);
return { foo : '次の処理' }; // 次のthenメソッドへ引き継ぐ
}).then(function(json) {
console.log(json);
});
なお、returnでPromiseを返すと次のthenメソッドは返したPromiseのthenメソッドとして処理されます。
JavaScript
new Promise(function(resolve) {
setTimeout(function() {
resolve('OK');
}, 2000);
}).then(function(message) {
console.log('解決', message);
return new Promise(function(resolve) {
setTimeout(function() {
resolve('OK2');
}, 1000);
});
}).then(function(message2) {
console.log(message2);
});
Promise.allメソッド
Promise.all
メソッドを使用する場合は次のようなコードで実装します。
JavaScript
const promise1 = new Promise(function(resolve) {
setTimeout(function() {
resolve('OK 1');
}, 1500);
});
const promise2 = new Promise(function(resolve) {
setTimeout(function() {
resolve('OK 2');
}, 500);
}).then(function(message) {
console.log(message);
});
const promise3 = new Promise(function(resolve) {
setTimeout(function() {
resolve('OK 3');
}, 1000);
});
Promise.all([promise1, promise2, promise3]).then(function(data) {
console.log('解決', data);
});
Promise.allメソッドは引数にPromiseを配列で指定します。
戻り値は単一のPromiseを返します。
Promise.allメソッドで繋がるthenメソッドは、Promise.allメソッドで指定した全てのPromiseが解決(resolve)した時のみ実行されます。
つまり1つでも拒否(reject)した場合は、Promise.allメソッドのthenメソッドは実行されずcatchメソッドが実行されます。
Promise.allメソッドで繋がるthenメソッドで受け取る引数は、resolve関数に指定した引数すべてを配列で返します。
Promise.race
Promise.race
メソッドを使用する場合は次のようなコードで実装します。
JavaScript
const promise1 = new Promise(function(resolve) {
setTimeout(function() {
resolve('OK 1');
}, 1500);
});
const promise2 = new Promise(function(resolve) {
setTimeout(function() {
resolve('OK 2');
}, 500);
});
const promise3 = new Promise(function(resolve) {
setTimeout(function() {
resolve('OK 3');
}, 1000);
});
Promise.race([promise1, promise2, promise3]).then(function(data) {
console.log('解決', data);
});
Promise.raceメソッドは引数にPromiseを配列で指定します。
戻り値は単一のPromiseを返します。
Promise.raceメソッドで繋がるthenメソッドは、Promise.raceメソッドで指定した何れか1つのPromiseが解決(resolve)した時に実行されます。
逆に1つでも拒否(reject)した場合は、Promise.raceメソッドのcatchメソッドが実行されます。
Promise.raceメソッドで繋がるthenメソッドで受け取る引数は、最初に解決されたresolve関数に指定した引数を返します。
ただし、解決されたPromiseにthenメソッドがある場合はそちらが優先され、Promise.raceメソッドで繋がるthenメソッドの引数はundefined
を返します。
正しい値を返してほしい場合は、解決されたPromiseにthenメソッドにreturnを使用して返すことで、その値が取得できます。
複数の処理を直列で実行
例えば次のようにファイルを読み込む関数loadFileがあり、引数で読み込みが終わった後に関数を実行するようなコードだとインデントが深くなっていきます。
JavaScript
loadFile('sample1.json', function() {
loadFile('sample2.json', function() {
loadFile('sample3.json', function() {
loadFile('sample4.json', function() {
loadFile('sample5.json', function() {
console.log('全て読み込み完了');
});
});
});
});
});
さらにif文などブロックが増えていくとインデントも深くなっていき、見づらくなっていきます。
こういった非同期で直列な処理の場合、Promiseを使用することでインデントが深くならずに下の方向に処理を書くことができます。
JavaScript
new Promise(function(resolve) {
loadFile('sample1.json', function() {
resolve();
});
}).then(function() {
return new Promise(function(resolve) {
loadFile('sample2.json', function() {
resolve();
});
});
}).then(function() {
return new Promise(function(resolve) {
loadFile('sample3.json', function() {
resolve();
});
});
}).then(function() {
return new Promise(function(resolve) {
loadFile('sample4.json', function() {
resolve();
});
});
}).then(function() {
return new Promise(function(resolve) {
loadFile('sample5.json', function() {
resolve();
});
});
}).finally(function() {
console.log('全て読み込み完了');
});
ファイルの読み込みが完了した後にresolve関数を実行しthenメソッドへ引き継ぎます。
thenメソッド内ではさらにPromiseを使用しreturnで返します。
これを繰り返すことで直列に処理されていきます。