async.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. //
  2. // wrap a function with setTimeout but let it be called like normal.
  3. //
  4. var delay = exports.delay = function (laters, time) {
  5. time = time || 0
  6. return function () {
  7. var args = [].slice.call(arguments)
  8. return setTimeout(function () {
  9. laters.apply(null, args)
  10. }, time)
  11. }
  12. }
  13. //
  14. // recursively compose async function.
  15. // the next function becomes the callback of the first
  16. // otherwise, the next function is called with the args of the first callback
  17. //
  18. // nothing special is done to the error parameter
  19. //
  20. exports.compose = compose
  21. function compose () {
  22. var funx = [].slice.call(arguments)
  23. if(funx.length <= 1)
  24. return funx[0]
  25. var f1 = funx.shift()
  26. var f2 = funx.shift()
  27. funx.unshift(function () {
  28. var args = [].slice.call(arguments)
  29. var callback = args.pop()
  30. args.push(function () {
  31. var args = [].slice.call(arguments)
  32. args.push(callback)
  33. f2.apply(this, args)
  34. })
  35. f1.apply(this, args)
  36. })
  37. return compose.apply(null, funx)
  38. }
  39. exports.fallthrough = fallthrough
  40. function fallthrough () {
  41. var args = [].slice.call(arguments)
  42. , callback = args.pop()
  43. args.unshift(null)
  44. callback.apply(this, args)
  45. }
  46. exports.tryCatchPass = tryCatchPass
  47. function tryCatchPass (_try,_catch,_pass) {
  48. //make _try safe
  49. return compose(safe(_try), function () {
  50. var args = [].slice.call(arguments)
  51. , next = args.pop()
  52. , err = args.shift()
  53. if(err && _catch)
  54. safe(_catch).call(this, err, next)
  55. else if (!err && _pass)
  56. safe(_pass).apply(null, args.concat(next))
  57. else
  58. next.apply(this, [err].concat(args))
  59. })
  60. }
  61. exports.safe = safe
  62. function fName (funx) {
  63. return '[' + (funx.name || funx.toString().slice(0,100) + '...') + ']'
  64. }
  65. function safe (funx) {
  66. var err = new Error( fName(funx) + ' called more than once')
  67. return function () {
  68. var _callback = arguments[arguments.length - 1]
  69. if('function' !== typeof _callback)
  70. (function (){ throw new Error('expected ' + _callback + 'to be a function') })()
  71. var n = 0
  72. , callback =
  73. arguments[arguments.length - 1] = function () {
  74. var args = [].slice.call(arguments)
  75. if(!n++)
  76. _callback.apply(this,args)
  77. else
  78. console.error(err.stack)
  79. //console.log('callback function ' + _callback.name + ' called:' + n + ' times')
  80. }
  81. try {
  82. funx.apply(null, arguments)
  83. } catch (err) {
  84. callback(err)
  85. }
  86. }
  87. }
  88. exports.toAsync = toAsync
  89. function toAsync (func, a, b) {
  90. return function () {
  91. var args = [].slice.call(arguments)
  92. , callback = args.pop()
  93. , r
  94. try {
  95. r = func.apply(this, args)
  96. } catch (err) {
  97. return callback (err)
  98. }
  99. callback (null, r)
  100. }
  101. }
  102. exports.timeout = function (func, time) {
  103. var err = new Error('timeout! function:' + (func.name || func.toString().slice(0,100)) + ' did not callback within ' + time)
  104. return function () {
  105. var args = [].slice.call(arguments)
  106. , callback = args.pop()
  107. , called = 0
  108. , timer = setTimeout(function () {
  109. checker(err)
  110. }, time)
  111. function checker () {
  112. clearTimeout(timer)
  113. if(! called ++)
  114. callback.apply(null, [].slice.call(arguments))
  115. }
  116. args.push(checker)
  117. return func.apply(this, args)
  118. }
  119. }