___do.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /* This file is part of AToMPM - A Tool for Multi-Paradigm Modelling
  2. * Copyright 2011 by the AToMPM team and licensed under the LGPL
  3. * See COPYING.lesser and README.md in the root of this project for full details
  4. */
  5. // Takes an array of actions and runs them all in parallel.
  6. // You can either pass in an array of actions, or several actions
  7. // as function arguments.
  8. // If you pass in an array, then the output will be an array of all the results
  9. // If you pass in separate arguments, then the output will have several arguments.
  10. exports.parallel = function parallel(actions) {
  11. if (!(Object.prototype.toString.call(actions) === '[object Array]')) {
  12. actions = Array.prototype.slice.call(arguments);
  13. var direct = true;
  14. }
  15. return function(callback, errback) {
  16. var results = [],
  17. counter = actions.length;
  18. actions.forEach(function (action, i) {
  19. action(function (result) {
  20. results[i] = result;
  21. counter--;
  22. if (counter <= 0) {
  23. if (direct) {
  24. callback.apply(null, results);
  25. } else {
  26. callback.call(null, results);
  27. }
  28. }
  29. }, errback);
  30. });
  31. };
  32. };
  33. // Chains together several actions feeding the output of the first to the
  34. // input of the second and the final output to the callback
  35. exports.chain = function chain(actions) {
  36. if (!(Object.prototype.toString.call(actions) === '[object Array]')) {
  37. actions = Array.prototype.slice.call(arguments);
  38. }
  39. return function(callback, errback) {
  40. var pos = 0;
  41. var length = actions.length;
  42. function loop(result) {
  43. pos++;
  44. if (pos >= length) {
  45. callback(result);
  46. } else {
  47. actions[pos](result)(loop, errback);
  48. }
  49. }
  50. actions[pos](loop, errback);
  51. };
  52. };
  53. // Takes an array and does an array map over it using the async callback `fn`
  54. // The signature of `fn` is `function fn(item, callback, errback)`
  55. exports.map = function map(array, fn) {
  56. return function (callback, errback) {
  57. var counter = array.length;
  58. var new_array = [];
  59. array.forEach(function (item, index) {
  60. var local_callback = function (result) {
  61. new_array[index] = result;
  62. counter--;
  63. if (counter <= 0) {
  64. new_array.length = array.length;
  65. callback(new_array);
  66. }
  67. };
  68. var cont = fn(item, local_callback, errback);
  69. if (typeof cont === 'function') {
  70. cont(local_callback, errback);
  71. }
  72. });
  73. };
  74. };
  75. // Takes an array and does an array filter over it using the async callback `fn`
  76. // The signature of `fn` is `function fn(item, callback, errback)`
  77. exports.filter = function filter(array, fn) { return function (callback, errback) {
  78. var counter = array.length;
  79. var valid = {};
  80. array.forEach(function (item, index) {
  81. var local_callback = function (result) {
  82. valid[index] = result;
  83. counter--;
  84. if (counter <= 0) {
  85. var result = [];
  86. array.forEach(function (item, index) {
  87. if (valid[index]) {
  88. result.push(item);
  89. }
  90. });
  91. callback(result);
  92. }
  93. };
  94. var cont = fn(item, local_callback, errback);
  95. if (typeof cont === 'function') {
  96. cont(local_callback, errback);
  97. }
  98. });
  99. };
  100. };
  101. // Takes an array and does a combined filter and map over it. If the result
  102. // of an item is undefined, then it's filtered out, otherwise it's mapped in.
  103. // The signature of `fn` is `function fn(item, callback, errback)`
  104. exports.filterMap = function filterMap(array, fn) { return function (callback, errback) {
  105. var counter = array.length;
  106. var new_array = [];
  107. array.forEach(function (item, index) {
  108. var local_callback = function (result) {
  109. new_array[index] = result;
  110. counter--;
  111. if (counter <= 0) {
  112. new_array.length = array.length;
  113. callback(new_array.filter(function (item) {
  114. return typeof item !== 'undefined';
  115. }));
  116. }
  117. };
  118. var cont = fn(item, local_callback, errback);
  119. if (typeof cont === 'function') {
  120. cont(local_callback, errback);
  121. }
  122. });
  123. };
  124. };
  125. // Allows to group several callbacks.
  126. // exports.combo = function combo(callback) {
  127. // var items = 0,
  128. // results = [];
  129. // function add() {
  130. // var id = items;
  131. // items++;
  132. // return function () {
  133. // check(id, arguments);
  134. // };
  135. // }
  136. // function check(id, arguments) {
  137. // results[id] = Array.prototype.slice.call(arguments);
  138. // items--;
  139. // if (items == 0) {
  140. // callback.apply(this, results);
  141. // }
  142. // }
  143. // return { add: add, check: check };
  144. // }
  145. // Takes any async lib that uses callback based signatures and converts
  146. // the specified names to continuable style and returns the new library.
  147. exports.convert = function (lib, names) {
  148. var newlib = {};
  149. Object.keys(lib).forEach(function (key) {
  150. if (names.indexOf(key) < 0) {
  151. return newlib[key] = lib[key];
  152. }
  153. newlib[key] = function () {
  154. var args = Array.prototype.slice.call(arguments);
  155. return function (callback, errback) {
  156. args.push(function (err, val) {
  157. if (err) {
  158. errback(err);
  159. } else {
  160. callback(val);
  161. }
  162. });
  163. lib[key].apply(lib, args);
  164. };
  165. };
  166. });
  167. return newlib;
  168. };