for (var v in nantoka()) yield v とか書かなくちゃいけなくね問題

案外そうでもなかったかもしれない。一個一個の関数を扱いにくいジェネレータ関数のまま放っておくのではなく、継続を引数にとる普通の非同期関数化してしまえばいいんだ。

お題は、これを出力するたびに0.1秒のウェイトいれるようにかえるというもの

function a() {
	for (var i = 0; i < 3; i ++) {
		console.log("a"+i);
	}
}

function b() {
	for (var i = 0; i < 3; i ++) {
		console.log("b"+i);
	}
}

function main() {
	a();
	b();
}

main();
console.log("done");

runnable関数はKazuho@Cybozu Labs: JavaScript/1.7 で協調的マルチスレッドより

function runnable(generatorFunc) {
	var generator;
	var resume = function (value) {
		try {
			generator.send(value);
		} catch (e if e instanceof StopIteration) {
		}
	};
	generator = generatorFunc(resume);
	resume(undefined);
}

function a(cont) {
	runnable(function (resume) {
		for (var i = 0; i < 3; i ++) {
			console.log("a"+i);
			setTimeout(resume, 100);
			yield;
		}
		cont();
	});
}

function b(cont) {
	runnable(function (resume) {
		for (var i = 0; i < 3; i ++) {
			console.log("b"+i);
			setTimeout(resume, 100);
			yield;
		}
		cont();
	});
}

function main(cont) {
	runnable(function (resume) {
		a(resume);
		yield;
		b(resume);
		yield;
		cont();
	});
}

main(function () {
	console.log("done");
});

まあこうするぐらいだったらdeferred-generatorの方が洗練されてるかなー

var a = Deferred.generator(function () {
	for (var i = 0; i < 3; i ++) {
		console.log("a"+i);
		yield Deferred.wait(0.1);
	}
});

var b = Deferred.generator(function () {
	for (var i = 0; i < 3; i ++) {
		console.log("b"+i);
		yield Deferred.wait(0.1);
	}
});

var main = Deferred.generator(function () {
	yield a();
	yield b();
});

main().then(function () {
	console.log("done");
});

ちなみに普通のDeferredライブラリ (ここではMochiKit) を使うとこう

var Async = MochiKit.Async;
function a() {
	return loop(0);
	function loop(i) {
		if (i >= 3) return Async.succeed();
		console.log("a"+i);
		return Async.callLater(0.1, loop, i + 1);
	}
}

function b() {
	return loop(0);
	function loop(i) {
		if (i >= 3) return Async.succeed();
		console.log("b"+i);
		return Async.callLater(0.1, loop, i + 1);
	}
}

function main() {
	var deferred = Async.succeed();
	deferred.addCallback(a);
	deferred.addCallback(b);
	return deferred;
	// return a().addCallback(b) でもいいんだけど気分的にaとbは同じ書き方で並べたい。
}

main().addCallback(function () {
	console.log("done");
});