utils.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. // This file contains all the non-ES6-standard helpers based on promise.
  2. module.exports = {
  3. /**
  4. * A function that helps run functions under a concurrent limitation.
  5. * To run functions sequentially, use `yaku/lib/flow`.
  6. * @param {Int} limit The max task to run at a time. It's optional.
  7. * Default is `Infinity`.
  8. * @param {Iterable} list Any [iterable](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols) object. It should be a lazy iteralbe object,
  9. * don't pass in a normal Array with promises.
  10. * @return {Promise}
  11. * @example
  12. * ```js
  13. * var kit = require('nokit');
  14. * var all = require('yaku/lib/all');
  15. *
  16. * var urls = [
  17. * 'http://a.com',
  18. * 'http://b.com',
  19. * 'http://c.com',
  20. * 'http://d.com'
  21. * ];
  22. * var tasks = function * () {
  23. * var i = 0;
  24. * yield kit.request(url[i++]);
  25. * yield kit.request(url[i++]);
  26. * yield kit.request(url[i++]);
  27. * yield kit.request(url[i++]);
  28. * }();
  29. *
  30. * all(tasks).then(() => kit.log('all done!'));
  31. *
  32. * all(2, tasks).then(() => kit.log('max concurrent limit is 2'));
  33. *
  34. * all(3, { next: () => {
  35. * var url = urls.pop();
  36. * return {
  37. * done: !url,
  38. * value: url && kit.request(url)
  39. * };
  40. * } })
  41. * .then(() => kit.log('all done!'));
  42. * ```
  43. */
  44. all: require("./all"),
  45. /**
  46. * Similar with the `Promise.race`, but only rejects when every entry rejects.
  47. * @param {iterable} iterable An iterable object, such as an Array.
  48. * @return {Yaku}
  49. * @example
  50. * ```js
  51. * var any = require('yaku/lib/any');
  52. * any([
  53. * 123,
  54. * Promise.resolve(0),
  55. * Promise.reject(new Error("ERR"))
  56. * ])
  57. * .then((value) => {
  58. * console.log(value); // => 123
  59. * });
  60. * ```
  61. */
  62. any: require("./any"),
  63. /**
  64. * Generator based async/await wrapper.
  65. * @param {Generator} gen A generator function
  66. * @return {Yaku}
  67. * @example
  68. * ```js
  69. * var async = require('yaku/lib/async');
  70. * var sleep = require('yaku/lib/sleep');
  71. *
  72. * var fn = async(function * () {
  73. * return yield sleep(1000, 'ok');
  74. * });
  75. *
  76. * fn().then(function (v) {
  77. * console.log(v);
  78. * });
  79. * ```
  80. */
  81. async: require("./async"),
  82. /**
  83. * If a function returns promise, convert it to
  84. * node callback style function.
  85. * @param {Function} fn
  86. * @param {Any} self The `this` to bind to the fn.
  87. * @return {Function}
  88. */
  89. callbackify: require("./callbackify"),
  90. /**
  91. * **deprecate** Create a `jQuery.Deferred` like object.
  92. * It will cause some buggy problems, please don't use it.
  93. */
  94. Deferred: require("./Deferred"),
  95. /**
  96. * Creates a function that is the composition of the provided functions.
  97. * See `yaku/lib/async`, if you need concurrent support.
  98. * @param {Iterable} list Any [iterable](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols) object. It should be a lazy iteralbe object,
  99. * don't pass in a normal Array with promises.
  100. * @return {Function} `(val) -> Promise` A function that will return a promise.
  101. * @example
  102. * It helps to decouple sequential pipeline code logic.
  103. * ```js
  104. * var kit = require('nokit');
  105. * var flow = require('yaku/lib/flow');
  106. *
  107. * function createUrl (name) {
  108. * return "http://test.com/" + name;
  109. * }
  110. *
  111. * function curl (url) {
  112. * return kit.request(url).then((body) => {
  113. * kit.log('get');
  114. * return body;
  115. * });
  116. * }
  117. *
  118. * function save (str) {
  119. * kit.outputFile('a.txt', str).then(() => {
  120. * kit.log('saved');
  121. * });
  122. * }
  123. *
  124. * var download = flow(createUrl, curl, save);
  125. * // same as "download = flow([createUrl, curl, save])"
  126. *
  127. * download('home');
  128. * ```
  129. * @example
  130. * Walk through first link of each page.
  131. * ```js
  132. * var kit = require('nokit');
  133. * var flow = require('yaku/lib/flow');
  134. *
  135. * var list = [];
  136. * function iter (url) {
  137. * return {
  138. * done: !url,
  139. * value: url && kit.request(url).then((body) => {
  140. * list.push(body);
  141. * var m = body.match(/href="(.+?)"/);
  142. * if (m) return m[0];
  143. * });
  144. * };
  145. * }
  146. *
  147. * var walker = flow(iter);
  148. * walker('test.com');
  149. * ```
  150. */
  151. flow: require("./flow"),
  152. /**
  153. * Enable a helper to catch specific error type.
  154. * It will be directly attach to the prototype of the promise.
  155. * @param {class} type
  156. * @param {Function} onRejected
  157. * @return {Promise}
  158. * ```js
  159. * var Promise = require('yaku');
  160. * require('yaku/lib/guard');
  161. *
  162. * class AnError extends Error {
  163. * }
  164. *
  165. * Promise.reject(new AnError('hey'))
  166. * .guard(AnError, (err) => {
  167. * // only log AnError type
  168. * console.log(err);
  169. * })
  170. * .then(() => {
  171. * console.log('done');
  172. * })
  173. * .guard(Error, (err) => {
  174. * // log all error type
  175. * console.log(err)
  176. * });
  177. * ```
  178. */
  179. guard: require("./guard"),
  180. /**
  181. * if-else helper
  182. * @param {Promise} cond
  183. * @param {Function} trueFn
  184. * @param {Function} falseFn
  185. * @return {Promise}
  186. * @example
  187. * ```js
  188. * var Promise = require('yaku');
  189. * var yutils = require('yaku/lib/utils');
  190. *
  191. * yutils.if(Promise.resolve(false), () => {
  192. * // true
  193. * }, () => {
  194. * // false
  195. * })
  196. * ```
  197. */
  198. "if": require("./if"),
  199. /**
  200. * **deprecate** Check if an object is a promise-like object.
  201. * Don't use it to coercive a value to Promise, instead use `Promise.resolve`.
  202. * @param {Any} obj
  203. * @return {Boolean}
  204. */
  205. isPromise: require("./isPromise"),
  206. /**
  207. * Create a promise that never ends.
  208. * @return {Promise} A promise that will end the current pipeline.
  209. */
  210. never: require("./never"),
  211. /**
  212. * Convert a node callback style function to a function that returns
  213. * promise when the last callback is not supplied.
  214. * @param {Function} fn
  215. * @param {Any} self The `this` to bind to the fn.
  216. * @return {Function}
  217. * @example
  218. * ```js
  219. * var promisify = require('yaku/lib/promisify');
  220. * function foo (val, cb) {
  221. * setTimeout(() => {
  222. * cb(null, val + 1);
  223. * });
  224. * }
  225. *
  226. * var bar = promisify(foo);
  227. *
  228. * bar(0).then((val) => {
  229. * console.log val // output => 1
  230. * });
  231. *
  232. * // It also supports the callback style.
  233. * bar(0, (err, val) => {
  234. * console.log(val); // output => 1
  235. * });
  236. * ```
  237. */
  238. promisify: require("./promisify"),
  239. /**
  240. * Create a promise that will wait for a while before resolution.
  241. * @param {Integer} time The unit is millisecond.
  242. * @param {Any} val What the value this promise will resolve.
  243. * @return {Promise}
  244. * @example
  245. * ```js
  246. * var sleep = require('yaku/lib/sleep');
  247. * sleep(1000).then(() => console.log('after one second'));
  248. * ```
  249. */
  250. sleep: require("./sleep"),
  251. /**
  252. * Read the `Observable` section.
  253. * @type {Function}
  254. */
  255. Observable: require("./Observable"),
  256. /**
  257. * Retry a function until it resolves before a mount of times, or reject with all
  258. * the error states.
  259. * @version_added v0.7.10
  260. * @param {Number | Function} countdown How many times to retry before rejection.
  261. * @param {Number} span Optional. How long to wait before each retry in millisecond.
  262. * When it's a function `(errs) => Boolean | Promise.resolve(Boolean)`,
  263. * you can use it to create complex countdown logic,
  264. * it can even return a promise to create async countdown logic.
  265. * @param {Function} fn The function can return a promise or not.
  266. * @param {Any} this Optional. The context to call the function.
  267. * @return {Function} The wrapped function. The function will reject an array
  268. * of reasons that throwed by each try.
  269. * @example
  270. * Retry 3 times before rejection, wait 1 second before each retry.
  271. * ```js
  272. * var retry = require('yaku/lib/retry');
  273. * var { request } = require('nokit');
  274. *
  275. * retry(3, 1000, request)('http://test.com').then(
  276. * (body) => console.log(body),
  277. * (errs) => console.error(errs)
  278. * );
  279. * ```
  280. * @example
  281. * Here a more complex retry usage, it shows an random exponential backoff algorithm to
  282. * wait and retry again, which means the 10th attempt may take 10 minutes to happen.
  283. * ```js
  284. * var retry = require('yaku/lib/retry');
  285. * var sleep = require('yaku/lib/sleep');
  286. * var { request } = require('nokit');
  287. *
  288. * function countdown (retries) {
  289. * var attempt = 0;
  290. * return async () => {
  291. * var r = Math.random() * Math.pow(2, attempt) * 1000;
  292. * var t = Math.min(r, 1000 * 60 * 10);
  293. * await sleep(t);
  294. * return attempt++ < retries;
  295. * };
  296. * }
  297. *
  298. * retry(countdown(10), request)('http://test.com').then(
  299. * (body) => console.log(body),
  300. * (errs) => console.error(errs)
  301. * );
  302. * ```
  303. */
  304. retry: require("./retry"),
  305. /**
  306. * Throw an error to break the program.
  307. * @param {Any} err
  308. * @example
  309. * ```js
  310. * var ythrow = require('yaku/lib/throw');
  311. * Promise.resolve().then(() => {
  312. * // This error won't be caught by promise.
  313. * ythrow('break the program!');
  314. * });
  315. * ```
  316. */
  317. "throw": require("./throw")
  318. };