___do.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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) { return function (callback, errback) {
  56. var counter = array.length;
  57. var new_array = [];
  58. array.forEach(function (item, index) {
  59. var local_callback = function (result) {
  60. new_array[index] = result;
  61. counter--;
  62. if (counter <= 0) {
  63. new_array.length = array.length
  64. callback(new_array);
  65. }
  66. };
  67. var cont = fn(item, local_callback, errback);
  68. if (typeof cont === 'function') {
  69. cont(local_callback, errback);
  70. }
  71. });
  72. }}
  73. // Takes an array and does an array filter over it using the async callback `fn`
  74. // The signature of `fn` is `function fn(item, callback, errback)`
  75. exports.filter = function filter(array, fn) { return function (callback, errback) {
  76. var counter = array.length;
  77. var valid = {};
  78. array.forEach(function (item, index) {
  79. var local_callback = function (result) {
  80. valid[index] = result;
  81. counter--;
  82. if (counter <= 0) {
  83. var result = [];
  84. array.forEach(function (item, index) {
  85. if (valid[index]) {
  86. result.push(item);
  87. }
  88. });
  89. callback(result);
  90. }
  91. };
  92. var cont = fn(item, local_callback, errback);
  93. if (typeof cont === 'function') {
  94. cont(local_callback, errback);
  95. }
  96. });
  97. }}
  98. // Takes an array and does a combined filter and map over it. If the result
  99. // of an item is undefined, then it's filtered out, otherwise it's mapped in.
  100. // The signature of `fn` is `function fn(item, callback, errback)`
  101. exports.filterMap = function filterMap(array, fn) { return function (callback, errback) {
  102. var counter = array.length;
  103. var new_array = [];
  104. array.forEach(function (item, index) {
  105. var local_callback = function (result) {
  106. new_array[index] = result;
  107. counter--;
  108. if (counter <= 0) {
  109. new_array.length = array.length;
  110. callback(new_array.filter(function (item) {
  111. return typeof item !== 'undefined';
  112. }));
  113. }
  114. };
  115. var cont = fn(item, local_callback, errback);
  116. if (typeof cont === 'function') {
  117. cont(local_callback, errback);
  118. }
  119. });
  120. }};
  121. // Allows to group several callbacks.
  122. exports.combo = function combo(callback) {
  123. var items = 0,
  124. results = [];
  125. function add() {
  126. var id = items;
  127. items++;
  128. return function () {
  129. check(id, arguments);
  130. };
  131. }
  132. function check(id, arguments) {
  133. results[id] = Array.prototype.slice.call(arguments);
  134. items--;
  135. if (items == 0) {
  136. callback.apply(this, results);
  137. }
  138. }
  139. return { add: add, check: check };
  140. }
  141. // Takes any async lib that uses callback based signatures and converts
  142. // the specified names to continuable style and returns the new library.
  143. exports.convert = function (lib, names) {
  144. var newlib = {};
  145. Object.keys(lib).forEach(function (key) {
  146. if (names.indexOf(key) < 0) {
  147. return newlib[key] = lib[key];
  148. }
  149. newlib[key] = function () {
  150. var args = Array.prototype.slice.call(arguments);
  151. return function (callback, errback) {
  152. args.push(function (err, val) {
  153. if (err) {
  154. errback(err);
  155. } else {
  156. callback(val);
  157. }
  158. });
  159. lib[key].apply(lib, args)
  160. }
  161. }
  162. });
  163. return newlib;
  164. }