非同期処理を行う

非同期処理を行うには、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で返します。
これを繰り返すことで直列に処理されていきます。

JavaScript逆引きリファレンス一覧へ戻る