対象のブラウザーがJavaScript1.7以降をサポートしている場合(執筆時点では、Geckoブラウザーのみがサポートしていると思います)、ジェネレーターを使用してこれを行うことができます。まず、connect
関数を非同期にします(テストは簡単にします)。
function connectAsync(callback) {
// Pretend we always succeed after a second.
// You could use some other asynchronous code instead.
setTimeout(callback, 1000, true);
}
次に、呼び出し元のコードを関数にラップします。(関数内にある必要があります。)
function main() {
console.log("Connecting...");
if(!(yield connect())) {
console.log("Failed to connect.");
yield; return;
}
console.log("Connected.");
yield;
}
yield
どこにでもあるすべてに注意してください。これは魔法の一部です。yield
呼び出すときとconnect
すべてのyield
関数出口点の前にが必要です。
次に、を定義する必要がありますconnect
。同期したい非同期関数がたくさんあるかもしれないので、関数を同期させる関数を作りましょう。
function synchronize(async) {
return function synchronous() {
return {func: async, args: arguments};
};
}
そして、それを使って作成できconnect
ますconnectAsync
。
var connect = synchronize(connectAsync);
次に、このすべての魔法を実行する関数を作成する必要があります。ここにあります:
function run(sync) {
var args = Array.prototype.slice.call(arguments);
var runCallback = args.length ? args[args.length - 1] : null;
if(args.length) {
args.splice(args.length - 1, 1);
}
var generator = sync.apply(window, args);
runInternal(generator.next());
function runInternal(value) {
if(typeof value === 'undefined') {
if(runCallback) {
return runCallback();
}else{
return;
}
}
function callback(result) {
return runInternal(generator.send(result));
}
var args = Array.prototype.slice.call(value.args);
args.push(callback);
value.func.apply(window, args);
}
}
main
これで、この魔法で関数を実行できます。
run(main);
main
値を返すことはできなくなったことに注意する必要があります。run
2番目の引数を取ることができます:同期関数が完了したときに呼び出されるコールバック。main
(たとえば、、、、1
および2
)に引数を渡すに3
は、次のように呼び出します。
run(main, 1, 2, 3, callback);
コールバックが必要ない場合は、null
またはを渡しundefined
ます。
これを試すにtype
は、script
タグのをに設定する必要がありますtext/javascript; version=1.7
。JavaScript 1.7は(のような)新しいキーワードを追加するyield
ため、下位互換性がなく、したがって、古いコードと区別するための何らかの方法が必要です。
ジェネレーターの詳細については、MDNのこのページを参照してください。コルーチンの詳細については、ウィキペディアの記事を参照してください。
とはいえ、JavaScript 1.7のサポートが限られているため、これは実用的ではありません。さらに、この種のコードを見るのは一般的ではないため、理解して維持するのが難しい場合があります。Deisssの回答に示されているように、非同期スタイルを使用することをお勧めします。ただし、これが可能であることは素晴らしいことです。