JSXのgeneratorで同期的なsleep()を実装してみる
[追記]v0.9.84現在、--enable-generator-emulationが必要です。これを付けないと、ES6のgeneratorを使うようにコンパイルされます。[/追記]
最近、JSの非同期まわりが新しい盛り上がりがありました。
Google Chromeに入ったジェネレータとPromiseで非同期処理に革命が起きた - 素人がプログラミングを勉強していたブログ
2013-05-02
とくにES6のgeneratorを使えば、非同期コードを同期的に書けるようになるということで期待が持てます。
ところで、JSXにも最近実験的にgeneratorが実装されました*1。生成されるJavaScriptはES5準拠ですから、スマートフォンでも実行可能です。
すなわち、これが本格的に使えるようになれば、ブラウザの対応を待たずにgeneratorが使い放題になるというわけですね!generatorを使いこなすのはかなり難しいのですが、静的型付けな分多少は開発もしやすいと思います ;)
なお、JSX generatorの正規リリースする際にはAPIが変更される可能性があります。ですから実験以外での使用は薦められませんのでご注意ください。
さて、このgeneratorを使えば、同期的に呼び出せるsleepは以下のように実装できます。setTimeout()を使った実装なのでもちろんUIをブロックしたりはしません。
/*JSX_OPTS --enable-generator-emulation */ /*** * Experimental generator */ import "timer.jsx"; class Async { static function sleep(durationMS : number) : (variant) -> void { return (g) -> { Timer.setTimeout(() -> { Async.go(g); }, durationMS); }; } static function run(coro : () -> void yield (variant)->void) : void { Async.go(coro()); } static function go(v : variant) : void { var g = v as Generator.<void, (variant)->void>; var data = g.next(); if (data.done) { return; // nothing } else { data.value(g); } } } class _Main { static function main(args : string[]) : void { Async.run(function * () : void yield (variant)->void { log "H"; yield Async.sleep(100); log "e"; yield Async.sleep(100); log "l"; yield Async.sleep(100); log "l"; yield Async.sleep(100); log "o"; }); } } // vim: set tabstop=2 shiftwidth=2 expandtab:
XMLHttpRequestの結果を待つこともできます。
// ... var s = ""; yield (g:variant) : void -> { var xhr = new XMLHttpRequest(); xhr.open("GET", "/index.html"); xhr.addEventListener("load", (event) -> { s = xhr.responseText; A.go(g); }); xhr.addEventListener("error", (event) -> { A.go(g); }); xhr.send(); }; log "response: " + s; // ...
*1:by id:wasabiz++