Top Related Projects
:bird: :zap: Bluebird is a full featured promise library with unmatched performance.
A promise library for JavaScript
Bare bones Promises/A+ implementation
Async utilities for node and the browser
Promise queue with concurrency control
Lightweight ES6 Promise polyfill for the browser and node. A+ Compliant
Quick Overview
RSVP.js is a lightweight library that provides tools for organizing asynchronous code in JavaScript. It implements Promises/A+ and works in node and the browser, offering a robust and efficient way to handle asynchronous operations.
Pros
- Lightweight and fast implementation of Promises
- Compatible with both browser and Node.js environments
- Follows the Promises/A+ specification for maximum interoperability
- Extensive API for advanced promise operations (e.g., all, race, hash)
Cons
- May be less necessary in modern JavaScript environments with native Promise support
- Limited ecosystem compared to some larger Promise libraries
- Requires understanding of Promise concepts for effective use
- Not actively maintained (last commit was in 2019)
Code Examples
- Basic Promise usage:
import RSVP from 'rsvp';
const promise = new RSVP.Promise((resolve, reject) => {
setTimeout(() => {
resolve('Success!');
}, 1000);
});
promise.then((value) => {
console.log(value); // Outputs: Success!
});
- Using
RSVP.all
to handle multiple promises:
const promise1 = RSVP.resolve(1);
const promise2 = RSVP.resolve(2);
const promise3 = RSVP.resolve(3);
RSVP.all([promise1, promise2, promise3]).then((values) => {
console.log(values); // Outputs: [1, 2, 3]
});
- Error handling with
catch
:
RSVP.Promise.resolve()
.then(() => {
throw new Error('Something went wrong');
})
.catch((error) => {
console.error(error.message); // Outputs: Something went wrong
});
Getting Started
To use RSVP.js in your project, first install it via npm:
npm install rsvp
Then, import and use it in your JavaScript code:
import RSVP from 'rsvp';
const myPromise = new RSVP.Promise((resolve, reject) => {
// Asynchronous operation here
if (/* operation successful */) {
resolve(result);
} else {
reject(new Error('Operation failed'));
}
});
myPromise
.then((result) => {
console.log('Success:', result);
})
.catch((error) => {
console.error('Error:', error);
});
This basic setup allows you to create and handle promises using RSVP.js in your project.
Competitor Comparisons
:bird: :zap: Bluebird is a full featured promise library with unmatched performance.
Pros of Bluebird
- Higher performance and faster execution compared to RSVP.js
- More extensive feature set, including advanced error handling and debugging capabilities
- Better browser support, especially for older versions
Cons of Bluebird
- Larger file size, which may impact load times for web applications
- Steeper learning curve due to its more comprehensive API
- Less frequent updates and maintenance in recent years
Code Comparison
RSVP.js:
RSVP.Promise.resolve(1)
.then(value => value + 1)
.then(value => console.log(value));
Bluebird:
Bluebird.resolve(1)
.then(value => value + 1)
.then(value => console.log(value));
The basic usage of both libraries is similar, but Bluebird offers additional methods and features for more complex scenarios. For example, Bluebird provides Promise.map()
for concurrent operations:
Bluebird.map([1, 2, 3], value => someAsyncOperation(value))
.then(results => console.log(results));
RSVP.js doesn't have a built-in equivalent, requiring manual implementation of concurrent operations.
A promise library for JavaScript
Pros of Q
- More comprehensive API with additional utility methods
- Better support for advanced error handling and debugging
- Wider adoption and longer history in the JavaScript community
Cons of Q
- Larger file size and potentially slower performance
- Steeper learning curve due to more complex API
- Less active maintenance and updates in recent years
Code Comparison
RSVP.js:
RSVP.Promise.resolve(value)
.then(result => {
// Handle result
})
.catch(error => {
// Handle error
});
Q:
Q.fcall(function () {
return value;
})
.then(function (result) {
// Handle result
})
.catch(function (error) {
// Handle error
});
Both libraries provide similar basic Promise functionality, but Q offers more verbose syntax for creating and chaining Promises. RSVP.js tends to have a more streamlined approach, while Q provides additional methods for more complex scenarios.
RSVP.js is generally lighter and faster, making it a good choice for simpler projects or performance-critical applications. Q, on the other hand, offers more features and flexibility, which can be beneficial for larger, more complex projects that require advanced Promise handling capabilities.
Bare bones Promises/A+ implementation
Pros of promise
- Smaller bundle size, making it more lightweight for browser usage
- Simpler API with fewer methods, potentially easier to learn and use
- Closer to the native Promise implementation in modern JavaScript
Cons of promise
- Less feature-rich compared to RSVP.js
- Fewer utility methods for advanced promise manipulation
- May require additional libraries or custom code for some complex scenarios
Code Comparison
RSVP.js:
RSVP.Promise.all([
RSVP.resolve(1),
RSVP.resolve(2),
RSVP.resolve(3)
]).then(function(results) {
console.log(results); // [1, 2, 3]
});
promise:
Promise.all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
]).then(function(results) {
console.log(results); // [1, 2, 3]
});
Both libraries provide similar functionality for basic promise operations. However, RSVP.js offers additional methods and features not present in promise, such as RSVP.hash()
for object-based promise resolution and RSVP.filter()
for array filtering with promises. promise focuses on providing a minimal, standards-compliant implementation of the Promise API.
Async utilities for node and the browser
Pros of async
- More comprehensive utility functions for asynchronous operations
- Better suited for complex control flow scenarios
- Supports both Node.js and browser environments
Cons of async
- Larger library size compared to RSVP.js
- Steeper learning curve due to more extensive API
- May be overkill for simpler promise-based workflows
Code Comparison
RSVP.js:
RSVP.Promise.all([promise1, promise2])
.then(function(results) {
// Handle results
})
.catch(function(error) {
// Handle error
});
async:
async.parallel([
function(callback) { /* task1 */ },
function(callback) { /* task2 */ }
], function(err, results) {
if (err) {
// Handle error
} else {
// Handle results
}
});
Summary
RSVP.js is a lightweight promise library focused on providing A+ compliant promises. It's ideal for projects that primarily need promise functionality without additional utilities.
async offers a broader range of asynchronous control flow utilities, making it more suitable for complex scenarios. However, this comes at the cost of a larger library size and potentially more complex usage.
The choice between the two depends on the specific needs of the project, with RSVP.js being more appropriate for simpler promise-based workflows and async being better suited for more complex asynchronous operations.
Promise queue with concurrency control
Pros of p-queue
- Focused on queue management with priority and concurrency control
- Supports TypeScript out of the box
- More actively maintained with frequent updates
Cons of p-queue
- Limited to queue functionality, not a full Promise library
- Smaller community and ecosystem compared to RSVP.js
- May require additional libraries for complex Promise operations
Code Comparison
RSVP.js:
RSVP.Promise.all([
getJSON('/posts'),
getJSON('/comments')
]).then(function(values) {
console.log(values[0], values[1]);
});
p-queue:
const queue = new PQueue({concurrency: 2});
queue.add(() => fetchSomething());
queue.add(() => fetchSomethingElse());
await queue.onIdle();
Summary
RSVP.js is a comprehensive Promise library with a focus on implementing the Promises/A+ specification. It provides a wide range of Promise-related utilities and has been around for a longer time, resulting in a larger ecosystem.
p-queue, on the other hand, is specifically designed for managing queues with Promises. It offers features like priority queuing and concurrency control, which are not directly available in RSVP.js. p-queue is more actively maintained and has better TypeScript support.
Choose RSVP.js for a full-featured Promise library, or p-queue for specialized queue management with Promises.
Lightweight ES6 Promise polyfill for the browser and node. A+ Compliant
Pros of promise-polyfill
- Lightweight and minimalistic, focusing solely on Promise functionality
- Easier to integrate into projects with simpler requirements
- Actively maintained with regular updates
Cons of promise-polyfill
- Limited feature set compared to RSVP.js
- Lacks advanced utilities and helper methods
- May require additional libraries for more complex asynchronous operations
Code Comparison
RSVP.js:
RSVP.Promise.resolve('foo').then(function(value) {
console.log(value);
});
RSVP.all([promise1, promise2]).then(function(values) {
console.log(values);
});
promise-polyfill:
Promise.resolve('foo').then(function(value) {
console.log(value);
});
Promise.all([promise1, promise2]).then(function(values) {
console.log(values);
});
Both libraries provide similar basic Promise functionality, but RSVP.js offers additional features and utilities beyond the standard Promise API. promise-polyfill focuses on providing a lightweight polyfill for environments lacking native Promise support, while RSVP.js aims to be a more comprehensive asynchronous library with extended capabilities.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
RSVP.js
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 thanRSVP.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 & testnpm test:node
- build & test just nodenpm test:server
- build/watch & testnpm run build
- Buildnpm 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
.
Top Related Projects
:bird: :zap: Bluebird is a full featured promise library with unmatched performance.
A promise library for JavaScript
Bare bones Promises/A+ implementation
Async utilities for node and the browser
Promise queue with concurrency control
Lightweight ES6 Promise polyfill for the browser and node. A+ Compliant
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot