_promisify.js 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. // freeze Array#slice, just in case of funny business later.
  2. var _slice = Array.prototype.slice;
  3. var getPromise = require('./_promise.js');
  4. // deferred gets its own scope to prevent inadvertent capture in the closure
  5. var deferred = function(options) {
  6. var Promise = getPromise();
  7. var resolve, reject, p = new Promise(function(_resolve, _reject) {
  8. resolve = _resolve; reject = _reject;
  9. });
  10. var pattern = (options && options.pattern);
  11. var noError = (options && options.noError);
  12. var cb = pattern ? function(err) {
  13. if (err && !noError) { return reject(err); }
  14. var result = {}, i, offset = noError ? 0 : 1;
  15. for (i = 0; i < pattern.length; i++) {
  16. result[pattern[i]] = arguments[i+offset];
  17. }
  18. resolve(result);
  19. } : noError ? resolve : function(err, val) {
  20. if (err) { reject(err); } else { resolve(val); }
  21. };
  22. return { promise: p, callback: cb };
  23. };
  24. var promisify = module.exports = function(context, func, mandatoryArgs, options) {
  25. if (options && options.callbackIsFirstArg) {
  26. // duplicate some code here so we don't have to process this unusual
  27. // situation at runtime in the common case.
  28. return function(cb) {
  29. if (typeof(cb) === 'function') {
  30. return func.apply(context, arguments);
  31. }
  32. var d = deferred(options);
  33. var a = _slice.call(arguments, 0);
  34. a.unshift(d.callback);
  35. func.apply(context, a);
  36. return d.promise;
  37. };
  38. }
  39. return function() {
  40. var cb = arguments[arguments.length - 1];
  41. if (typeof(cb) === 'function') {
  42. return func.apply(context, arguments);
  43. }
  44. // ooh, promises.
  45. var d = deferred(options);
  46. var a = _slice.call(arguments, 0);
  47. while (a.length < mandatoryArgs) { a.push(undefined); }
  48. a.push(d.callback);
  49. var retval = func.apply(context, a);
  50. if (options && options.returnsObject) {
  51. // it would be nice to have a better convention here
  52. Object.defineProperty(retval, 'promise', { value: d.promise });
  53. return retval;
  54. }
  55. return d.promise;
  56. };
  57. };