非同期処理の待ち合わせ
非同期処理の実行完了を待ち合わせるユーティリティを書いてみました。
要件
複数の非同期処理を実行し、すべての処理の実行完了後に特定の処理を実行したい。
実装
JavaScriptはシングルスレッドで動作しているらしいので同期化は不要。こんなのでいいはずです。
- コンストラクタで「すべての処理の実行完了後に行う処理」と「待つ処理の数」を渡す。
- 非同期処理で実行する関数にWait#createCallBack()で処理の完了を通知する機能を付加して実行。(または、実行完了後にWait#createCallBack()で作成した関数を実行し、処理の完了を通知する。)
- 非同期処理の実行後に、完了した処理数のカウンタを増やし、「待つ処理の数」と同じになったら、「すべての処理の実行完了後に行う処理」を実行する。
/*** * 複数の非同期処理の実行を待ち合わせるユーティリティ * @param {Function} finish すべてのコマンドの実行完了後に呼び出される。 * @param {Integer} commandLength コマンドの数。 */ function Wait( finish, commandLength ) { this.count = 0; this.commandLength = commandLength; this.finish = finish; } Wait.prototype = { /** * 処理完了を通知するコールバック関数を生成する。 * 引数でコールバック関数が渡された場合、その関数に処理完了を通知する機能を付加する。 * @param {Function} callback 委譲先コールバック関数。 */ createCallBack: function( callback ) { var thiz = this; return function( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 ){ try { if ( callback ) { callback( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 ); // これはひどい。 } } finally { thiz.count += 1; if ( thiz.count == thiz.commandLength ) { // 指定回数の呼び出しが完了したら // コールバック関数を実行する。 thiz.finish(); } } }; } }
サンプル
以下のような感じで使います。
var stdout = document.getElementById("stdout"); // Wait オブジェクトを作成。 // 引数で待ちあわせ終了時に実行する処理と待ち数を指定する。 var wait = new Wait( function() { stdout.innerHTML += "<br/>end."; }, 100 ); for ( var i = 0; i < 100; i++ ) { // 0〜10秒の間でランダムにxを出力。 // 実行する関数に待ち合わせ完了通知機能を付加する。 setTimeout( wait.createCallBack( function() { stdout.innerHTML += "x"; }), Math.random() * 10000 ); }