Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

rsvp

tildeio17.5mMIT4.8.5TypeScript support: definitely-typed

A lightweight library that provides tools for organizing asynchronous code

futures, promises

readme

RSVP.js Build Status Inline docs

RSVP.js provides simple tools for organizing asynchronous code.

Specifically, it is a tiny implementation of Promises/A+.

It works in node and the browser (IE9+, all the popular evergreen ones).

downloads

CDN

<script src="https://cdn.jsdelivr.net/npm/rsvp@4/dist/rsvp.min.js"></script>

Promises

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.

Node

yarn add --save rsvp
# or ...
npm install --save rsvp

RSVP.Promise is an implementation of Promises/A+ that passes the test suite.

It delivers all promises asynchronously, even if the value is already available, to help you write consistent code that doesn't change if the underlying data provider changes from synchronous to asynchronous.

It is compatible with TaskJS, a library by Dave Herman of Mozilla that uses ES6 generators to allow you to write synchronous code with promises. It currently works in Firefox, and will work in any browser that adds support for ES6 generators. See the section below on TaskJS for more information.

Basic Usage

var RSVP = require('rsvp');

var promise = new RSVP.Promise(function(resolve, reject) {
  // succeed
  resolve(value);
  // or reject
  reject(error);
});

promise.then(function(value) {
  // success
}).catch(function(error) {
  // failure
});

Once a promise has been resolved or rejected, it cannot be resolved or rejected again.

Here is an example of a simple XHR2 wrapper written using RSVP.js:

var getJSON = function(url) {
  var promise = new RSVP.Promise(function(resolve, reject){
    var client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

    function handler() {
      if (this.readyState === this.DONE) {
        if (this.status === 200) { resolve(this.response); }
        else { reject(this); }
      }
    };
  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  // continue
}).catch(function(error) {
  // handle errors
});

Chaining

One of the really awesome features of Promises/A+ promises are that they can be chained together. In other words, the return value of the first resolve handler will be passed to the second resolve handler.

If you return a regular value, it will be passed, as is, to the next handler.

getJSON("/posts.json").then(function(json) {
  return json.post;
}).then(function(post) {
  // proceed
});

The really awesome part comes when you return a promise from the first handler:

getJSON("/post/1.json").then(function(post) {
  // save off post
  return getJSON(post.commentURL);
}).then(function(comments) {
  // proceed with access to post and comments
});

This allows you to flatten out nested callbacks, and is the main feature of promises that prevents "rightward drift" in programs with a lot of asynchronous code.

Errors also propagate:

getJSON("/posts.json").then(function(posts) {

}).catch(function(error) {
  // since no rejection handler was passed to the
  // first `.then`, the error propagates.
});

You can use this to emulate try/catch logic in synchronous code. Simply chain as many resolve callbacks as you want, and add a failure handler at the end to catch errors.

getJSON("/post/1.json").then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // proceed with access to posts and comments
}).catch(function(error) {
  // handle errors in either of the two requests
});

Error Handling

There are times when dealing with promises that it seems like any errors are being 'swallowed', and not properly raised. This makes it extremely difficult to track down where a given issue is coming from. Thankfully, RSVP has a solution for this problem built in.

You can register functions to be called when an uncaught error occurs within your promises. These callback functions can be anything, but a common practice is to call console.assert to dump the error to the console.

RSVP.on('error', function(reason) {
  console.assert(false, reason);
});

RSVP allows Promises to be labeled: Promise.resolve(value, 'I AM A LABEL') If provided, this label is passed as the second argument to RSVP.on('error')

RSVP.on('error', function(reason, label) {
  if (label) {
    console.error(label);
  }

  console.assert(false, reason);
});

NOTE: promises do allow for errors to be handled asynchronously, so this callback may result in false positives.

Finally

finally will be invoked regardless of the promise's fate, just as native try/catch/finally behaves.

findAuthor().catch(function(reason){
  return findOtherAuthor();
}).finally(function(){
  // author was either found, or not
});

Arrays of promises

Sometimes you might want to work with many promises at once. If you pass an array of promises to the all() method it will return a new promise that will be fulfilled when all of the promises in the array have been fulfilled; or rejected immediately if any promise in the array is rejected.

var promises = [2, 3, 5, 7, 11, 13].map(function(id){
  return getJSON("/post/" + id + ".json");
});

RSVP.all(promises).then(function(posts) {
  // posts contains an array of results for the given promises
}).catch(function(reason){
  // if any of the promises fails.
});

Hash of promises

If you need to reference many promises at once (like all()), but would like to avoid encoding the actual promise order you can use hash(). If you pass an object literal (where the values are promises) to the hash() method it will return a new promise that will be fulfilled when all of the promises have been fulfilled; or rejected immediately if any promise is rejected.

The key difference to the all() function is that both the fulfillment value and the argument to the hash() function are object literals. This allows you to simply reference the results directly off the returned object without having to remember the initial order like you would with all().

var promises = {
  posts: getJSON("/posts.json"),
  users: getJSON("/users.json")
};

RSVP.hash(promises).then(function(results) {
  console.log(results.users) // print the users.json results
  console.log(results.posts) // print the posts.json results
});

All settled and hash settled

Sometimes you want to work with several promises at once, but instead of rejecting immediately if any promise is rejected, as with all() or hash(), you want to be able to inspect the results of all your promises, whether they fulfill or reject. For this purpose, you can use allSettled() and hashSettled(). These work exactly like all() and hash(), except that they fulfill with an array or hash (respectively) of the constituent promises' result states. Each state object will either indicate fulfillment or rejection, and provide the corresponding value or reason. The states will take one of the following formats:

{ state: 'fulfilled', value: value }
  or
{ state: 'rejected', reason: reason }

Deferred

The RSVP.Promise constructor is generally a better, less error-prone choice than RSVP.defer(). Promises are recommended unless the specific properties of deferred are needed.

Sometimes one needs to create a deferred object, without immediately specifying how it will be resolved. These deferred objects are essentially a wrapper around a promise, whilst providing late access to the resolve() and reject() methods.

A deferred object has this form: { promise, resolve(x), reject(r) }.

var deferred = RSVP.defer();
// ...
deferred.promise // access the promise
// ...
deferred.resolve();

TaskJS

The TaskJS library makes it possible to take promises-oriented code and make it synchronous using ES6 generators.

Let's review an earlier example:

getJSON("/post/1.json").then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // proceed with access to posts and comments
}).catch(function(reason) {
  // handle errors in either of the two requests
});

Without any changes to the implementation of getJSON, you could write the following code with TaskJS:

spawn(function *() {
  try {
    var post = yield getJSON("/post/1.json");
    var comments = yield getJSON(post.commentURL);
  } catch(error) {
    // handle errors
  }
});

In the above example, function * is new syntax in ES6 for generators. Inside a generator, yield pauses the generator, returning control to the function that invoked the generator. In this case, the invoker is a special function that understands the semantics of Promises/A, and will automatically resume the generator as soon as the promise is resolved.

The cool thing here is the same promises that work with current JavaScript using .then will work seamlessly with TaskJS once a browser has implemented it!

Instrumentation

function listener (event) {
  event.guid      // guid of promise. Must be globally unique, not just within the implementation
  event.childGuid // child of child promise (for chained via `then`)
  event.eventName // one of ['created', 'chained', 'fulfilled', 'rejected']
  event.detail    // fulfillment value or rejection reason, if applicable
  event.label     // label passed to promise's constructor
  event.timeStamp // milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now
  event.stack     // stack at the time of the event. (if  'instrument-with-stack' is true)
}

RSVP.configure('instrument', true | false);
// capturing the stacks is slow, so you also have to opt in
RSVP.configure('instrument-with-stack', true | false);

// events
RSVP.on('created', listener);
RSVP.on('chained', listener);
RSVP.on('fulfilled', listener);
RSVP.on('rejected', listener);

Events are only triggered when RSVP.configure('instrument') is true, although listeners can be registered at any time.

Building & Testing

Custom tasks:

  • npm test - build & test
  • npm test:node - build & test just node
  • npm test:server - build/watch & test
  • npm run build - Build
  • npm run build:production - Build production (with minified output)
  • npm start - build, watch and run interactive server at http://localhost:4200'

Releasing

Check what release-it will do by running npm run-script dry-run-release. To actually release, run node_modules/.bin/release-it.

changelog

Master

4.8.5

  • remove try/catch performance hacks, modern runtimes no longer require these tricks
  • internal tooling improvements

4.8.2

  • restore cast for 4.x

4.8.1

  • Confuse Webpack (make is easier to pack this module)

4.8.0

  • reject promise when non-array promise is passed to RSVP.filter
  • fix issue with registering event callbacks
  • remove publishing to S3 and rely on npm and jsdelivr.com instead
  • general cleanup

4.7.0

  • Release the same code as 4.0.2 but as 4.7.0 (fixes issues with npm outdated, yarn update-interactive, etc caused by accidental publishing of 4.6.1).

4.0.2

  • Fix issue which occurs when you have a .finally after a promise has rejected with no rejection value.

4.0.1

  • Fix bug in RSVP.filter where it would only respect explicitly true values (unlike [].filter which allows truthy values).

4.0.0

  • remove es3 fallbacks
  • make map/filter eager

3.5.0

  • expose RSVP.asap for access to the micro-task polyfil

3.4.0

  • [BUGFIX] Fix memory leak [#446]
  • Mirror Node's LTS policy
  • add dist/rsvp.es.js (bundle as a single ES module file)
  • fix typo in readme

3.3.3

  • [BUGFIX] Fix asap for Titanium \w webpack usage.

3.3.2

  • [BUGFIX] fix invalid ES6

3.3.1

  • [BUGFIX] for compat, ensure both default export and property export exist. This will likely go away in 4.0.0, and was the result of rollup producing proper output with __esModule: true brand

3.3.0

  • improve build, switch to broccoli-rollup (among other things)
  • RSVP.filter() now itself accepts a Promise.all as input
  • compress and mangle prod build output
  • [REVERT] reject instead of throwing, spec violation.

3.2.1

  • reject instead of throwing

3.2.0

  • add tamper protection - then / resolve tampering should avoid fast-paths the rely on those being predictable
  • improve performance of Enumerator operating on non-promise objects
  • Ensure the promise constructor continues to get inlined.

3.1.0

  • RSVP.on('error', function(reason, label) { ... } now also provides the rejected promises label.

3.0.21

  • actually don't publish built tests to npm

3.0.20

  • correctly publish bower & npm

3.0.19

  • don't publish built tests to npm

3.0.18

  • issue with phantomjs 2.0 on travis. I have lost patience..
  • test on iojs and node 0.12
  • bump ember-cli
  • Support objects not inheriting from Object.prototype in RSVP.hash()

3.0.17

  • Added browser field to fix browserification
  • Fix stripping source map
  • Fix duplicate imports
  • Remove unused loader.js dependency
  • Add the ember-cli dependency checker
  • Remove the duplicate build script
  • Remove the static middleware
  • add npm run build:production
  • browserify extern not needed
  • also add lib for those es6 peeps
  • enusre only dist is included in publishes
  • strip source maps for now.
  • copy correct tree into test
  • prefer start to server
  • use git-repo-version
  • ah, prod builds used rename correctly.
  • remove rename, prefer mv for this scenario
  • prepend license
  • Revert "node 0.10.x doesn’t like this. Its not really needed just run npm run test or npm run test:ci"
  • node 0.10.x doesn’t like this. Its not really needed just run npm run test or npm run test:ci
  • move stuff around + bump to broccoli-stew 0.0.3
  • bump broccoli-stew which now supports globs
  • Problem with path for vertx.js.

3.0.16

  • use more supported version of export default
  • more broccoli fun
  • remove accidentally imported map file
  • test non-minified (we can add a flag to test minified next)
  • [BUGFIX release] Replace closure compiler

3.0.15

  • Added Node 0.11 to travis ci test runner
  • Replaced deprecated process.nextTick with setImmediate
  • Ember test and npm run test:node passing
  • (origin/upgrade-tooling) upgrade tooling
  • Fix onerror test
  • [fixes #322] don't inform instrumentation of errors until the current turn is complete.
  • Follow thenable state not own state
  • Correct minor spelling error in defer doc example
  • Set [[AlreadyResolved]] as soon as resolve is called
  • Finally should correctly trigger on('error')
  • [fixes #294] finally work correctly with on(‘error’)
  • Use git-repo-version to calculate build signature
  • yay the new transpiler supports this now!!!
  • Use the latest version of the transpiler
  • add subclassing tests to finally
  • extern event emitter stuff
  • [fixes #309] some more externs
  • ensure those select few using node with minified JS don't have an issue
  • [fixes #302] use @calvinmetcalf’s promises-aplus-tests-phantom

3.0.14

  • Instrumentation with stack is now opt-in
  • improve cost of instrumentation by up to 15x in chrome
  • reduce AST size
  • last vertex related touch-ups.
  • Add vert.x compatibility.
  • [fixes #296] for define.amd and module.exports to no minify
  • [fixes #292] ensure the deferred's api doesn't break when minified
  • ignore some files for npm
  • Add 'finally' to readme
  • Use browserify assert instead of vendoring one
  • Use mocha and json3 from npm, not bower
  • Remove unused json2 file
  • upgrade build tooling
  • improve performance of instrumentation (also add seperate flag to include "stack" with instrumentation as it is unfortunately slow)
  • ensure minified RSVP.defer() maintains known external API #293
  • add finally to the readme
  • improve usage of browserify for promise/a+ tests
  • add wasteful files to gitignore
  • add vert.x compatibility

3.0.13

  • [Bugfix] fix RSVP.hash RSVP.hashSettled in runtimes < es5 by fixing a broken Object.create polyfil #286
  • [Enhancement] cleanup & improve test related build tooling #288

3.0.12

  • [Bugfix] fix regression in denodeify that broke foreign thenables as arguments to denodeifed functions #281

3.0.11

  • [Bugfix] some onerror scenarios did not result in error notifications 4dcf
  • [Bugfix] for more correctness internal optimization should only occure if constructors equal, not just if instanceof check passes 96b5ec
  • fancy new s3 publishing thanks to @rondale-sc

3.0.10

  • faster denodeify
  • rework tooling (Broccoli, testem, no grunt)
  • utilize bundle format for super small UMD builds

3.0.9

  • [Bugfix] no longer include promise-aplus tests as a production dependency
  • [Enhancement] fast then path for both rejection/fulfilment 0d252
  • [Enhancement] short-cut for faster then chaining in specific scenarios #256

3.0.8

  • [Bugfix] custom onerror handler, for potentially unhandled errors would report unhandled errors in some incorrect scenarios. #255

3.0.7

  • improve tests in some older es5+ browsers
  • [Bugfix] denodeify should not use console for deprecation warning unless console is defined
  • [Enhancement] instrumentation should emit out-of-band. This should improve ember-extension performance
  • [Bugfix] race should not be susceptible to zalgo
  • [Perf] PromiseEnumerator increase performance of all enumerable methods all/allSettled/hash/hasSettled -> https://gist.github.com/stefanpenner/26465d5848f2924e2aca
  • [Docfix] Fix small documentation inconsistency
  • [Perf] an internal promise shouldn't bother validating this and resolver
  • [Perf] flatten asap’s QUEUE structure
  • [Perf] Reduce Constructor AST size.
  • [Perf] some versions of v8, think keep marking these functions to be optimized. This hints to them not to be.
  • [Perf] accidental resolve step, that merely needed to be a fulfill
  • [Perf/Enhancement] simplify publishing
  • [Spec ADdition]add spec test “Ensure then is always called with a clean stack.” ensure RSVP passes future a+ spec
  • [Bugfix] web worker support
  • [Docfix] Add a param name to make yuidoc happy
  • [Enhancement] simplify async vs sync pub/sub code-paths
  • [Bugfix] Passed the label through to the Promise object, as expected
  • [Docfix] missing Parentheses on promise example in documentation
  • [License] Add Stefan Penner to license
  • [Docfix] document var promises in filter.js

3.0.3 -> 3.0.6 (missing changelog)

  • Changes to RSVP.denodeify: Behaviour for multiple success callback parameters has been improved and the denodefied function now inherits from the original node function.

3.0.2

  • [Spec compliance] Promise.all and Promise.race should reject, not throw on invalid input
  • Add RSVP.allSettled

3.0.1

  • Optimization: promises with noop resolvers now don't bother try to handle them.
  • [perf] skip costly resolver invocation if it is known not to be needed.
  • improve promise inspector interopt

3.0.0

  • align with the promise spec https://github.com/domenic/promises-unwrapping
  • idiomatic es6 usage
  • RSVP.all: now casts rather then resolves, and doesn't touch the "then"
  • RSVP.hash: now casts rather then resolves, and doesn't touch the "then"
  • MutationObserver: prefer text mutation, this fixes interop with MutationObserver polyfils
  • Removing asap unload listener. Allows back/forward page cache, chrome bug is old. Fixes #168
  • add grunt docs task
  • document: Promise.cast
  • document: Promise.resolve/Promise.reject
  • document: Promise.race
  • document: Promise.all
  • document: Promise.hash
  • document: RSVP.denodeify
  • document: RSVP.EventTarget
  • document: RSVP.rethrow
  • document: RSVP.defer
  • Document: RSVP.on('error'
  • Add Instrumentation hooks for tooling
  • Significant internal cleanup and performance improvements
  • require Promise constructor to be new'd (aligned with es6 spec)
  • Prefer tasks + config inline within project
  • Add Promise.finally
  • Add Promise.cast
  • Add Promise.resolve
  • Add Promise.reject
  • Add Promise.all
  • Add Promise.race
  • Add RSVP.map
  • Support promise inheritance
  • optimize onerror and reduce promise creation cost by 20x
  • promise/a+ 2.0.3 compliant
  • RSVP.async to schedule callbacks on internal queue
  • Optimization: only enforce a single nextTick for each queue flush.

2.0.4

  • Fix npm package

2.0.3

  • Fix useSetTimeout bug

2.0.2

  • Adding RSVP#rethrow
  • add pre-built AMD link to README
  • adding promise#fail

2.0.1

  • misc IE fixes, including IE array detection
  • upload passing builds to s3
  • async: use three args for addEventListener
  • satisfy both 1.0 and 1.1 specs
  • Run reduce tests only in node
  • RSVP.resolve now simply uses the internal resolution procedure
  • prevent multiple promise resolutions
  • simplify thenable handling
  • pre-allocate the deferred's shape
  • Moved from Rake-based builds to Grunt
  • Fix Promise subclassing bug
  • Add RSVP.configure('onerror')
  • Throw exception when RSVP.all is called without an array
  • refactor RSVP.all to just use a promise directly
  • Make RSVP.denodeify pass along thisArg
  • add RSVP.reject
  • Reject promise if resolver function throws an exception
  • add travis build-status
  • correctly test and fix self fulfillment
  • remove promise coercion.
  • Fix infinite recursion with deep self fulfilling promises
  • doc fixes

2.0.0

  • No changelog beyond this point. Here be dragons.