index.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. 'use strict';
  2. var isPromise = require('is-promise');
  3. /**
  4. * Return a function that will run a function asynchronously or synchronously
  5. *
  6. * example:
  7. * runAsync(wrappedFunction, callback)(...args);
  8. *
  9. * @param {Function} func Function to run
  10. * @param {Function} cb Callback function passed the `func` returned value
  11. * @return {Function(arguments)} Arguments to pass to `func`. This function will in turn
  12. * return a Promise (Node >= 0.12) or call the callbacks.
  13. */
  14. var runAsync = module.exports = function (func, cb) {
  15. cb = cb || function () {};
  16. return function () {
  17. var args = arguments;
  18. var promise = new Promise(function (resolve, reject) {
  19. var resolved = false;
  20. const wrappedResolve = function (value) {
  21. if (resolved) {
  22. console.warn('Run-async promise already resolved.')
  23. }
  24. resolved = true;
  25. resolve(value);
  26. }
  27. var rejected = false;
  28. const wrappedReject = function (value) {
  29. if (rejected) {
  30. console.warn('Run-async promise already rejected.')
  31. }
  32. rejected = true;
  33. reject(value);
  34. }
  35. var usingCallback = false;
  36. var callbackConflict = false;
  37. var contextEnded = false;
  38. var answer = func.apply({
  39. async: function () {
  40. if (contextEnded) {
  41. console.warn('Run-async async() called outside a valid run-async context, callback will be ignored.');
  42. return function() {};
  43. }
  44. if (callbackConflict) {
  45. console.warn('Run-async wrapped function (async) returned a promise.\nCalls to async() callback can have unexpected results.');
  46. }
  47. usingCallback = true;
  48. return function (err, value) {
  49. if (err) {
  50. wrappedReject(err);
  51. } else {
  52. wrappedResolve(value);
  53. }
  54. };
  55. }
  56. }, Array.prototype.slice.call(args));
  57. if (usingCallback) {
  58. if (isPromise(answer)) {
  59. console.warn('Run-async wrapped function (sync) returned a promise but async() callback must be executed to resolve.');
  60. }
  61. } else {
  62. if (isPromise(answer)) {
  63. callbackConflict = true;
  64. answer.then(wrappedResolve, wrappedReject);
  65. } else {
  66. wrappedResolve(answer);
  67. }
  68. }
  69. contextEnded = true;
  70. });
  71. promise.then(cb.bind(null, null), cb);
  72. return promise;
  73. }
  74. };
  75. runAsync.cb = function (func, cb) {
  76. return runAsync(function () {
  77. var args = Array.prototype.slice.call(arguments);
  78. if (args.length === func.length - 1) {
  79. args.push(this.async());
  80. }
  81. return func.apply(this, args);
  82. }, cb);
  83. };