Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

3 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. # RSVP.js [![Build Status](https://secure.travis-ci.org/tildeio/rsvp.js.svg?branch=master)](http://travis-ci.org/tildeio/rsvp.js) [![Inline docs](http://inch-ci.org/github/tildeio/rsvp.js.svg?branch=master)](http://inch-ci.org/github/tildeio/rsvp.js)
  2. RSVP.js provides simple tools for organizing asynchronous code.
  3. Specifically, it is a tiny implementation of Promises/A+.
  4. It works in node and the browser (IE6+, all the popular evergreen ones).
  5. ## downloads
  6. - [rsvp-latest](http://rsvpjs-builds.s3.amazonaws.com/rsvp-latest.js)
  7. - [rsvp-latest (minified)](http://rsvpjs-builds.s3.amazonaws.com/rsvp-latest.min.js)
  8. ## Promises
  9. Although RSVP is ES6 compliant, it does bring along some extra toys. If you would prefer a strict ES6 subset, I would suggest checking out our sibling project https://github.com/stefanpenner/es6-promise, It is RSVP but stripped down to the ES6 spec features.
  10. ## Bower
  11. `bower install -S rsvp`
  12. ## NPM
  13. `npm install --save rsvp`
  14. `RSVP.Promise` is an implementation of
  15. [Promises/A+](http://promises-aplus.github.com/promises-spec/) that passes the
  16. [test suite](https://github.com/promises-aplus/promises-tests).
  17. It delivers all promises asynchronously, even if the value is already
  18. available, to help you write consistent code that doesn't change if the
  19. underlying data provider changes from synchronous to asynchronous.
  20. It is compatible with [TaskJS](http://taskjs.org/), a library by Dave
  21. Herman of Mozilla that uses ES6 generators to allow you to write
  22. synchronous code with promises. It currently works in Firefox, and will
  23. work in any browser that adds support for ES6 generators. See the
  24. section below on TaskJS for more information.
  25. ### Basic Usage
  26. ```javascript
  27. var RSVP = require('rsvp');
  28. var promise = new RSVP.Promise(function(resolve, reject) {
  29. // succeed
  30. resolve(value);
  31. // or reject
  32. reject(error);
  33. });
  34. promise.then(function(value) {
  35. // success
  36. }).catch(function(error) {
  37. // failure
  38. });
  39. ```
  40. Once a promise has been resolved or rejected, it cannot be resolved or
  41. rejected again.
  42. Here is an example of a simple XHR2 wrapper written using RSVP.js:
  43. ```javascript
  44. var getJSON = function(url) {
  45. var promise = new RSVP.Promise(function(resolve, reject){
  46. var client = new XMLHttpRequest();
  47. client.open("GET", url);
  48. client.onreadystatechange = handler;
  49. client.responseType = "json";
  50. client.setRequestHeader("Accept", "application/json");
  51. client.send();
  52. function handler() {
  53. if (this.readyState === this.DONE) {
  54. if (this.status === 200) { resolve(this.response); }
  55. else { reject(this); }
  56. }
  57. };
  58. });
  59. return promise;
  60. };
  61. getJSON("/posts.json").then(function(json) {
  62. // continue
  63. }).catch(function(error) {
  64. // handle errors
  65. });
  66. ```
  67. ### Chaining
  68. One of the really awesome features of Promises/A+ promises are that they
  69. can be chained together. In other words, the return value of the first
  70. resolve handler will be passed to the second resolve handler.
  71. If you return a regular value, it will be passed, as is, to the next
  72. handler.
  73. ```javascript
  74. getJSON("/posts.json").then(function(json) {
  75. return json.post;
  76. }).then(function(post) {
  77. // proceed
  78. });
  79. ```
  80. The really awesome part comes when you return a promise from the first
  81. handler:
  82. ```javascript
  83. getJSON("/post/1.json").then(function(post) {
  84. // save off post
  85. return getJSON(post.commentURL);
  86. }).then(function(comments) {
  87. // proceed with access to post and comments
  88. });
  89. ```
  90. This allows you to flatten out nested callbacks, and is the main feature
  91. of promises that prevents "rightward drift" in programs with a lot of
  92. asynchronous code.
  93. Errors also propagate:
  94. ```javascript
  95. getJSON("/posts.json").then(function(posts) {
  96. }).catch(function(error) {
  97. // since no rejection handler was passed to the
  98. // first `.then`, the error propagates.
  99. });
  100. ```
  101. You can use this to emulate `try/catch` logic in synchronous code.
  102. Simply chain as many resolve callbacks as a you want, and add a failure
  103. handler at the end to catch errors.
  104. ```javascript
  105. getJSON("/post/1.json").then(function(post) {
  106. return getJSON(post.commentURL);
  107. }).then(function(comments) {
  108. // proceed with access to posts and comments
  109. }).catch(function(error) {
  110. // handle errors in either of the two requests
  111. });
  112. ```
  113. ## Error Handling
  114. There are times when dealing with promises that it seems like any errors
  115. are being 'swallowed', and not properly raised. This makes it extremely
  116. difficult to track down where a given issue is coming from. Thankfully,
  117. `RSVP` has a solution for this problem built in.
  118. You can register functions to be called when an uncaught error occurs
  119. within your promises. These callback functions can be anything, but a common
  120. practice is to call `console.assert` to dump the error to the console.
  121. ```javascript
  122. RSVP.on('error', function(reason) {
  123. console.assert(false, reason);
  124. });
  125. ```
  126. `RSVP` allows Promises to be labeled: `Promise.resolve(value, 'I AM A LABEL')`
  127. If provided, this label is passed as the second argument to `RSVP.on('error')`
  128. ```javascript
  129. RSVP.on('error', function(reason, label) {
  130. if (label) {
  131. console.error(label);
  132. }
  133. console.assert(false, reason);
  134. });
  135. ```
  136. **NOTE:** promises do allow for errors to be handled asynchronously, so
  137. this callback may result in false positives.
  138. ## Finally
  139. `finally` will be invoked regardless of the promise's fate, just as native
  140. try/catch/finally behaves.
  141. ```js
  142. findAuthor().catch(function(reason){
  143. return findOtherAuthor();
  144. }).finally(function(){
  145. // author was either found, or not
  146. });
  147. ```
  148. ## Arrays of promises
  149. Sometimes you might want to work with many promises at once. If you
  150. pass an array of promises to the `all()` method it will return a new
  151. promise that will be fulfilled when all of the promises in the array
  152. have been fulfilled; or rejected immediately if any promise in the array
  153. is rejected.
  154. ```javascript
  155. var promises = [2, 3, 5, 7, 11, 13].map(function(id){
  156. return getJSON("/post/" + id + ".json");
  157. });
  158. RSVP.all(promises).then(function(posts) {
  159. // posts contains an array of results for the given promises
  160. }).catch(function(reason){
  161. // if any of the promises fails.
  162. });
  163. ```
  164. ## Hash of promises
  165. If you need to reference many promises at once (like `all()`), but would like
  166. to avoid encoding the actual promise order you can use `hash()`. If you pass
  167. an object literal (where the values are promises) to the `hash()` method it will
  168. return a new promise that will be fulfilled when all of the promises have been
  169. fulfilled; or rejected immediately if any promise is rejected.
  170. The key difference to the `all()` function is that both the fulfillment value
  171. and the argument to the `hash()` function are object literals. This allows
  172. you to simply reference the results directly off the returned object without
  173. having to remember the initial order like you would with `all()`.
  174. ```javascript
  175. var promises = {
  176. posts: getJSON("/posts.json"),
  177. users: getJSON("/users.json")
  178. };
  179. RSVP.hash(promises).then(function(results) {
  180. console.log(results.users) // print the users.json results
  181. console.log(results.posts) // print the posts.json results
  182. });
  183. ```
  184. ## All settled and hash settled
  185. Sometimes you want to work with several promises at once, but instead of
  186. rejecting immediately if any promise is rejected, as with `all()` or `hash()`,
  187. you want to be able to inspect the results of all your promises, whether
  188. they fulfill or reject. For this purpose, you can use `allSettled()` and
  189. `hashSettled()`. These work exactly like `all()` and `hash()`, except that
  190. they fulfill with an array or hash (respectively) of the constituent promises'
  191. result states. Each state object will either indicate fulfillment or
  192. rejection, and provide the corresponding value or reason. The states will take
  193. one of the following formats:
  194. ```javascript
  195. { state: 'fulfilled', value: value }
  196. or
  197. { state: 'rejected', reason: reason }
  198. ```
  199. ## Deferred
  200. > The `RSVP.Promise` constructor is generally a better, less error-prone choice
  201. > than `RSVP.defer()`. Promises are recommended unless the specific
  202. > properties of deferred are needed.
  203. Sometimes one needs to create a deferred object, without immediately specifying
  204. how it will be resolved. These deferred objects are essentially a wrapper around
  205. a promise, whilst providing late access to the `resolve()` and `reject()` methods.
  206. A deferred object has this form: `{ promise, resolve(x), reject(r) }`.
  207. ```javascript
  208. var deferred = RSVP.defer();
  209. // ...
  210. deferred.promise // access the promise
  211. // ...
  212. deferred.resolve();
  213. ```
  214. ## TaskJS
  215. The [TaskJS](http://taskjs.org/) library makes it possible to take
  216. promises-oriented code and make it synchronous using ES6 generators.
  217. Let's review an earlier example:
  218. ```javascript
  219. getJSON("/post/1.json").then(function(post) {
  220. return getJSON(post.commentURL);
  221. }).then(function(comments) {
  222. // proceed with access to posts and comments
  223. }).catch(function(reason) {
  224. // handle errors in either of the two requests
  225. });
  226. ```
  227. Without any changes to the implementation of `getJSON`, you could write
  228. the following code with TaskJS:
  229. ```javascript
  230. spawn(function *() {
  231. try {
  232. var post = yield getJSON("/post/1.json");
  233. var comments = yield getJSON(post.commentURL);
  234. } catch(error) {
  235. // handle errors
  236. }
  237. });
  238. ```
  239. In the above example, `function *` is new syntax in ES6 for
  240. [generators](http://wiki.ecmascript.org/doku.php?id=harmony:generators).
  241. Inside a generator, `yield` pauses the generator, returning control to
  242. the function that invoked the generator. In this case, the invoker is a
  243. special function that understands the semantics of Promises/A, and will
  244. automatically resume the generator as soon as the promise is resolved.
  245. The cool thing here is the same promises that work with current
  246. JavaScript using `.then` will work seamlessly with TaskJS once a browser
  247. has implemented it!
  248. ## Instrumentation
  249. ```js
  250. function listener (event) {
  251. event.guid // guid of promise. Must be globally unique, not just within the implementation
  252. event.childGuid // child of child promise (for chained via `then`)
  253. event.eventName // one of ['created', 'chained', 'fulfilled', 'rejected']
  254. event.detail // fulfillment value or rejection reason, if applicable
  255. event.label // label passed to promise's constructor
  256. event.timeStamp // milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now
  257. event.stack // stack at the time of the event. (if 'instrument-with-stack' is true)
  258. }
  259. RSVP.configure('instrument', true | false);
  260. // capturing the stacks is slow, so you also have to opt in
  261. RSVP.configure('instrument-with-stack', true | false);
  262. // events
  263. RSVP.on('created', listener);
  264. RSVP.on('chained', listener);
  265. RSVP.on('fulfilled', listener);
  266. RSVP.on('rejected', listener);
  267. ```
  268. Events are only triggered when `RSVP.configure('instrument')` is true, although
  269. listeners can be registered at any time.
  270. ## Building & Testing
  271. Custom tasks:
  272. * `npm test` - build & test
  273. * `npm test:node` - build & test just node
  274. * `npm test:server` - build/watch & test
  275. * `npm run build` - Build
  276. * `npm run build:production` - Build production (with minified output)
  277. * `npm start` - build, watch and run interactive server at http://localhost:4200'
  278. ## Releasing
  279. Check what release-it will do by running `npm run-script dry-run-release`.
  280. To actually release, run `node_modules/.bin/release-it`.