◆ Promise にして見やすく
◆ 呼び出す時を普通に関数実行できるように変更
◆ 非同期関数を複数実行しておいて await (yield) は値が欲しいところで使う方法は JavaScript でもできた



前回は ES7 で入るらしい async/await を Generator で作りましたが

非同期処理のある関数を実行する時は
acall(sample_gen, "この後にURLのデータ:")

待機したい非同期関数を実行するときは
var text = yield afunc(httpGet, "/")

となんか微妙でした

それと シンプルにするために昔ながらのコールバック関数で Promise にしてませんでした

そのあたりを改善してみたものです

コード

用意しておくコード
function async(args, gen){
  return new Promise((resolve, reject) => {
  var ite = gen(...args)
  !function recur(pre_value){
  var ret = ite.next(pre_value)
  ret.done ? resolve(ret.value) : ret.value.then(recur)
  }()
  })
}

wait してみる
function wait(msec){
  return new Promise((resolve, reject) => {
  setTimeout(resolve, msec)
  })
}

function async_test(){
  return async(arguments, function*(a,b){
  console.log("wait", Date.now())
  yield wait(1000)
  console.log("waitend", Date.now())
  console.log(a, b)
  })
}

async_test(1, 2)
wait 1455961206662
waitend 1455961207666
1 2

fetch してみる
function test(){return async(arguments, function*(){
  var f1 = fetch("/").then(e => e.text())
  var f2 = fetch("/test.jpg").then(e => e.blob())

  var text = yield f1
  console.log(text.substr(0,14))
  var blob = yield f2
  console.log(blob)
})}

test()
<!doctype html
Blob {}


非同期処理が入る async で定義する関数自体は 普通の関数にして 内部でジェネレータを作って 非同期制御用の async 関数に渡すような作りです
ちょっと書くこと多くなりますが 2 つ目の fetch のほうの例みたいに一行でコピペで書いてしまえばそんなに困りませんし 呼び出すときに関数名と引数を呼び出し用の関数に渡すという setTimeout みたいな書き方をしなくて済みます

定義より呼び出すほうが多いので 呼び出しの方を楽にしました

また Promise にした分 await の代わりの yield 周りもスッキリしました


前に 別言語の await だと 非同期実行は連続して実行しておいて 値が必要なところで await を変数に対して実行するというものがありましたが yield では値を受け取っているだけなので JavaScript でも同じことができました

2 つ目の方では fetch().then() は先に 2 つやっておいて ほしいところで yield で待機させています


しくみを単純に言ってしまえば yield に Promise を渡せば Promise が解決するまでそこで待機して 解決したらその値を yield の返り値で受け取れる というものです