◆ ES7 の async await 機能が便利そう
◆ ジェネレータで近いことをやってみます 

前にジェネレータで非同期関数を楽にできないかなーとこんなのを作ってましたが 結局いままでと大差ない非同期処理を配列に並べて順に実行していくだけでした

ですが 最近 async await という仕組みを知って 「おー便利! しかも yield で近いことできそう 」 と思ったのでやってみることにします

async/await

ES7 からのものらしいです
JavaScript が最初に導入する仕組みってものでもなく Python だったり .NET などでも使われている言葉です

構文では c# のに近そう?

ぐぐってみても あれこれライブラリ使ってみましたとかでシンプルにどういう書き方でどう動くかを綺麗にまとめてるのが見当たらなかったのですが 簡単にまとめるとこんなものなようです
(公式 spec も何かと複雑で見づらくてパスしました)
async function sample(){
var val = await asyncFunction(1)
console.log(val)
}
sample()

asyncFunction は非同期な関数です
普通は 非同期関数の返り値では目的のものが入っていないです
Promise を返して返り値を通してやることを then でセットだけしておいて 結果が来たらやるっていうのが最近の方法かと思いますが await を使えば そこでちゃんとストップして続きからしてくれるそうです
await を使う関数には目印に async をつけておきます

val にはいきなりほしい値が入っていて Promise を通す必要もないのです

すっごく便利そうです!!!

ジェネレータで頑張る

でも await で待機してデータが来たら続きをやるっていうのは 一度中断してあとから続きをやるジェネレータの yield に似てますよね
ここまで簡単にはできないですが 近いことをやってみようと思います
function acall(gen, ...args){
var ite = gen(...args)
!function recur(pre_value){
var ret = ite.next(pre_value)
ret.done || ret.value(recur)
}()
}

function afunc(fn, ...args){
return cb => fn(...args, cb)
}
こんな関数を準備します

非同期な関数には URL を指定してダウンロードするものとスリープを用意します
function httpGet(url, cb){
fetch(url).then(e => e.text()).then(e => cb(e))
}

function wait(msec, cb){
setTimeout(cb, msec)
}

メイン部分はこんなのです
function* sample_gen(message){
console.log("wait", Date.now())
yield afunc(wait, 1000)
console.log("waitend", Date.now())
var text = yield afunc(httpGet, "/")
console.log(message)
console.log(text)
}

acall(sample_gen, "この後にURLのデータ:")

実行すると……
wait 1455345512307
waitend 1455345513308
この後にURLのデータ:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTM...............

おぉ。。
ちゃんとできてますね

スリープのところも差がだいたい 1000 ですし 書いた通りの並びで実行されています

使い方

async の代わりにジェネレータじるしの * をつけます
await の代わりに yield afunc( ) を書きます
afunc は関数で引数には 非同期な関数とその関数を呼び出す時の引数を渡します
async 関数を実行するときは acall 関数に async 関数とその関数に渡す引数を渡します

これだけでおっけい
かなり楽に使えるのではと思います


今回はあまり複雑にしたくなかったので中では Promise じゃなくて 昔ながらのコールバック関数を使っています
なので wait などの非同期関数を作るときには最後にコールバック関数を受け取るようにしておかないとダメで それと afunc の呼び出しでは引数の省略ができなかったりでちょっと不便です
まぁこれは Promise にしたら扱いやすくなるのかと思います

あとは try catch
やるなら acall 関数が Promise 作ってそこで受け取るくらいしかできないのかな
async 関数内で await 部分を含んで try catch を書かれてもどうしようもなさそう

これだけ?

ところで 別言語の async をみていると await の後の関数が非同期関数って言うものじゃなさそうな例もありました
async function sample(){
var aval = asyncFunction(1)
console.log("ここは直ぐに表示")
var val = await aval
console.log(val)
}
sample()

JavaScript で再現してますが たしかこんな感じです
await なしで非同期関数を実行して その値が必要になるところまでは進めます
「ここは直ぐに表示」というのはすぐに表示されます

そして await があるところまで行くと await で指定された変数に値が入るまで待つようです
ちょっと複雑ですが この機能もありかなと思います

JavaScript のを簡単に見た感じではこういう例は見当たらなかったのですが どうなるんでしょう