CoffeeScriptで、コルーチン無しで、非同期逐次実行を平たく書く


ちっぽけだけど、npmに上げよう

なんつーか、npmモジュールの練習にもってこいかも知れない。日曜か、今日の仕事の具合によっては今晩。

内容としては補遺

コルーチンを出すまでもなく、非同期処理を書こうとすればどの制御構造も書ける。というのを以前のエントリで示した。が、やっぱり即時関数の引数に無名関数を書く、なんていうのは、慣れていない人にはトリッキーに見えるかも知れない。なので、_forなどで見せたように、関数の中にそういうトリッキーな部分を閉じ込めればいい。

たとえば、こんな風にブロック毎に任意の数の引数が受け渡せて、しかも逐次実行を保証してくれるとしたらどうだろう。

_continuation ['firstarg1','arg2']
, (next,str1,str2) ->

  #block1
  PRINT str1,->
    PRINT str2,->
      C ->
        D ->
          next 'err'

, (next,errstr) ->

  #block2
  PRINT errstr,->
    F ->
      if true
        G -> next()
      else
        next()

, (next) ->

  #block3
  H ->
    I ->
      return

引数もブロックをまたいで渡せて、if~elseブロックからの合流もできる。合流する前に複数の飛び先が欲しいなら、引数としてステータスを表す文字列を渡してswitchすればいい。これなら、コルーチン欲しー、と言う人も、あえ? このほうがいいかも? と寝返るかも知れない。

そんなわけで、上記の_continuationも書いてみた。

y_combi = (func) ->
  return ((p) ->
    return () ->
      return func(p(p)).apply(this,arguments)
  )((p) ->
    return () ->
      return func(p(p)).apply(this,arguments)
  )

_continuation = ->
  args = [].slice.call(arguments)
  firstargs = args.shift()
  (y_combi (func) ->
    return ->
      arg = args.shift()
      if arg?
        passargs = [].slice.call(arguments)
        passargs.unshift(func)
        arg.apply(this,passargs)
  ).apply(this,firstargs)

#for test

A = (func) -> console.log 'A'; setTimeout func, 500
B = (func) -> console.log 'B'; setTimeout func, 500
C = (func) -> console.log 'C'; setTimeout func, 500
D = (func) -> console.log 'D'; setTimeout func, 500
E = (func) -> console.log 'E'; setTimeout func, 500
F = (func) -> console.log 'F'; setTimeout func, 500
G = (func) -> console.log 'G'; setTimeout func, 500
H = (func) -> console.log 'H'; setTimeout func, 500
I = (func) -> console.log 'I'; setTimeout func, 500
PRINT = (str,func) -> console.log 'PRINT: '+str; setTimeout func, 500

どうかな。