promise.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*!
  2. * Module dependencies
  3. */
  4. var MPromise = require('mpromise');
  5. var util = require('util');
  6. /**
  7. * Promise constructor.
  8. *
  9. * Promises are returned from executed queries. Example:
  10. *
  11. * var query = Candy.find({ bar: true });
  12. * var promise = query.exec();
  13. *
  14. * @param {Function} fn a function which will be called when the promise is resolved that accepts `fn(err, ...){}` as signature
  15. * @inherits mpromise https://github.com/aheckmann/mpromise
  16. * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
  17. * @event `err`: Emits when the promise is rejected
  18. * @event `complete`: Emits when the promise is fulfilled
  19. * @api public
  20. */
  21. function Promise (fn) {
  22. MPromise.call(this, fn);
  23. }
  24. /*!
  25. * Inherit from mpromise
  26. */
  27. Promise.prototype = Object.create(MPromise.prototype, {
  28. constructor: {
  29. value: Promise
  30. , enumerable: false
  31. , writable: true
  32. , configurable: true
  33. }
  34. });
  35. /*!
  36. * Override event names for backward compatibility.
  37. */
  38. Promise.SUCCESS = 'complete';
  39. Promise.FAILURE = 'err';
  40. /**
  41. * Adds `listener` to the `event`.
  42. *
  43. * If `event` is either the success or failure event and the event has already been emitted, the`listener` is called immediately and passed the results of the original emitted event.
  44. *
  45. * @see mpromise#on https://github.com/aheckmann/mpromise#on
  46. * @method on
  47. * @memberOf Promise
  48. * @param {String} event
  49. * @param {Function} listener
  50. * @return {Promise} this
  51. * @api public
  52. */
  53. /**
  54. * Rejects this promise with `reason`.
  55. *
  56. * If the promise has already been fulfilled or rejected, not action is taken.
  57. *
  58. * @see mpromise#reject https://github.com/aheckmann/mpromise#reject
  59. * @method reject
  60. * @memberOf Promise
  61. * @param {Object|String|Error} reason
  62. * @return {Promise} this
  63. * @api public
  64. */
  65. /**
  66. * Rejects this promise with `err`.
  67. *
  68. * If the promise has already been fulfilled or rejected, not action is taken.
  69. *
  70. * Differs from [#reject](#promise_Promise-reject) by first casting `err` to an `Error` if it is not `instanceof Error`.
  71. *
  72. * @api public
  73. * @param {Error|String} err
  74. * @return {Promise} this
  75. */
  76. Promise.prototype.error = function (err) {
  77. if (!(err instanceof Error)) {
  78. if (err instanceof Object) {
  79. err = util.inspect(err);
  80. }
  81. err = new Error(err);
  82. }
  83. return this.reject(err);
  84. }
  85. /**
  86. * Resolves this promise to a rejected state if `err` is passed or a fulfilled state if no `err` is passed.
  87. *
  88. * If the promise has already been fulfilled or rejected, not action is taken.
  89. *
  90. * `err` will be cast to an Error if not already instanceof Error.
  91. *
  92. * _NOTE: overrides [mpromise#resolve](https://github.com/aheckmann/mpromise#resolve) to provide error casting._
  93. *
  94. * @param {Error} [err] error or null
  95. * @param {Object} [val] value to fulfill the promise with
  96. * @api public
  97. */
  98. Promise.prototype.resolve = function (err) {
  99. if (err) return this.error(err);
  100. return this.fulfill.apply(this, Array.prototype.slice.call(arguments, 1));
  101. };
  102. /**
  103. * Adds a single function as a listener to both err and complete.
  104. *
  105. * It will be executed with traditional node.js argument position when the promise is resolved.
  106. *
  107. * promise.addBack(function (err, args...) {
  108. * if (err) return handleError(err);
  109. * console.log('success');
  110. * })
  111. *
  112. * Alias of [mpromise#onResolve](https://github.com/aheckmann/mpromise#onresolve).
  113. *
  114. * _Deprecated. Use `onResolve` instead._
  115. *
  116. * @method addBack
  117. * @param {Function} listener
  118. * @return {Promise} this
  119. * @deprecated
  120. */
  121. Promise.prototype.addBack = Promise.prototype.onResolve;
  122. /**
  123. * Fulfills this promise with passed arguments.
  124. *
  125. * @method fulfill
  126. * @receiver Promise
  127. * @see https://github.com/aheckmann/mpromise#fulfill
  128. * @param {any} args
  129. * @api public
  130. */
  131. /**
  132. * Fulfills this promise with passed arguments.
  133. *
  134. * Alias of [mpromise#fulfill](https://github.com/aheckmann/mpromise#fulfill).
  135. *
  136. * _Deprecated. Use `fulfill` instead._
  137. *
  138. * @method complete
  139. * @receiver Promise
  140. * @param {any} args
  141. * @api public
  142. * @deprecated
  143. */
  144. Promise.prototype.complete = MPromise.prototype.fulfill;
  145. /**
  146. * Adds a listener to the `complete` (success) event.
  147. *
  148. * Alias of [mpromise#onFulfill](https://github.com/aheckmann/mpromise#onfulfill).
  149. *
  150. * _Deprecated. Use `onFulfill` instead._
  151. *
  152. * @method addCallback
  153. * @param {Function} listener
  154. * @return {Promise} this
  155. * @api public
  156. * @deprecated
  157. */
  158. Promise.prototype.addCallback = Promise.prototype.onFulfill;
  159. /**
  160. * Adds a listener to the `err` (rejected) event.
  161. *
  162. * Alias of [mpromise#onReject](https://github.com/aheckmann/mpromise#onreject).
  163. *
  164. * _Deprecated. Use `onReject` instead._
  165. *
  166. * @method addErrback
  167. * @param {Function} listener
  168. * @return {Promise} this
  169. * @api public
  170. * @deprecated
  171. */
  172. Promise.prototype.addErrback = Promise.prototype.onReject;
  173. /**
  174. * Creates a new promise and returns it. If `onFulfill` or `onReject` are passed, they are added as SUCCESS/ERROR callbacks to this promise after the nextTick.
  175. *
  176. * Conforms to [promises/A+](https://github.com/promises-aplus/promises-spec) specification.
  177. *
  178. * ####Example:
  179. *
  180. * var promise = Meetups.find({ tags: 'javascript' }).select('_id').exec();
  181. * promise.then(function (meetups) {
  182. * var ids = meetups.map(function (m) {
  183. * return m._id;
  184. * });
  185. * return People.find({ meetups: { $in: ids }).exec();
  186. * }).then(function (people) {
  187. * if (people.length < 10000) {
  188. * throw new Error('Too few people!!!');
  189. * } else {
  190. * throw new Error('Still need more people!!!');
  191. * }
  192. * }).then(null, function (err) {
  193. * assert.ok(err instanceof Error);
  194. * });
  195. *
  196. * @see promises-A+ https://github.com/promises-aplus/promises-spec
  197. * @see mpromise#then https://github.com/aheckmann/mpromise#then
  198. * @method then
  199. * @memberOf Promise
  200. * @param {Function} onFulFill
  201. * @param {Function} onReject
  202. * @return {Promise} newPromise
  203. */
  204. /**
  205. * Signifies that this promise was the last in a chain of `then()s`: if a handler passed to the call to `then` which produced this promise throws, the exception will go uncaught.
  206. *
  207. * ####Example:
  208. *
  209. * var p = new Promise;
  210. * p.then(function(){ throw new Error('shucks') });
  211. * setTimeout(function () {
  212. * p.fulfill();
  213. * // error was caught and swallowed by the promise returned from
  214. * // p.then(). we either have to always register handlers on
  215. * // the returned promises or we can do the following...
  216. * }, 10);
  217. *
  218. * // this time we use .end() which prevents catching thrown errors
  219. * var p = new Promise;
  220. * var p2 = p.then(function(){ throw new Error('shucks') }).end(); // <--
  221. * setTimeout(function () {
  222. * p.fulfill(); // throws "shucks"
  223. * }, 10);
  224. *
  225. * @api public
  226. * @see mpromise#end https://github.com/aheckmann/mpromise#end
  227. * @method end
  228. * @memberOf Promise
  229. */
  230. /*!
  231. * expose
  232. */
  233. module.exports = Promise;