npm install babel -g
experimentalオプション必須なので コンパイルは babel -e foo.es6 > foo.js
みたいな感じ
適当に試してみた。
import "babel/polyfill";
let wait = function(n: number){
return new Promise(done => setTimeout(() => done(n), n));
};
let main = async function(){
await wait(50);
console.log('await done');
}
// async promise nomally
wait(100).then(() => console.log('promise normaly done'));
// await
main();
最初awaitブロックがasyncを取るのが必須なことに気づかなくて、普通に呼ぼうとしてちょっとハマった。まあ処理系やポリフィルの都合そうなるのはなんとなくわかる。
これasync () => {...}
や await () => {...}
みたいな Arrow Functionでも動くのかなぁと思って次のコード試してみた。
import "babel/polyfill";
(async () => {
await new Promise(done => setTimeout(() => {console.log('done 1'); done()}, 100));
await new Promise(done => setTimeout(() => {console.log('done 2'); done()}, 100));
})()
じゃあワンライナーもいけるじゃんと試してみたら動いた
import "babel/polyfill";
(async () => await new Promise(done => setTimeout(() => {console.log('wait done'); done()}, 1000)))()
吐かれたコード読んでみる。
"use strict";
var _this = this;
require("babel/polyfill");
(function callee$0$0() {
return regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
context$1$0.next = 2;
return new Promise(function (done) {
return setTimeout(function () {
console.log("wait done");done();
}, 1000);
});
case 2:
return context$1$0.abrupt("return", context$1$0.sent);
case 3:
case "end":
return context$1$0.stop();
}
}, null, _this);
})();
あんまり読みたくはないのが出てきたが… とりあえず追っていったところ https://github.com/babel/regenerator-babel/blob/master/runtime.js を使っている。
https://github.com/babel/regenerator-babel/blob/master/runtime.js#L96-L119 をみたところGeneratorってのでwrapしてPromiseをキューにしてさばき終えるのを待ってて、割と素直だった。というかAST読んでからの式変形の実装が強そう。(これCPS変換って言っていいんだろうか)
babel/polyfillがcommonjs requireのままなのでブラウザに持ってくにはbrowserify前提な感じ。
式からawaitの出現数を数えてcase作ってるようにみえたので、forで回すちょっと意地悪なコード書いてみる。
import "babel/polyfill";
(async () => {
for(var i = 0; i < 10; i++){
await new Promise(done => setTimeout(() => {console.log('wait done'); done()}, 100));
}
})();
ちゃんと動いた。が、出力みて頭かしげた。
"use strict";
var _this = this;
require("babel/polyfill");
(function callee$0$0() {
var i;
return regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
i = 0;
case 1:
if (!(i < 10)) {
context$1$0.next = 7;
break;
}
context$1$0.next = 4;
return new Promise(function (done) {
return setTimeout(function () {
console.log("wait done");done();
}, 100);
});
case 4:
i++;
context$1$0.next = 1;
break;
case 7:
case "end":
return context$1$0.stop();
}
}, null, _this);
})();
これ、いわゆるswitchによるgoto… なんかllvmがCから出力したIRみたいだ。
なんか納得感あったのでこれで終わり。