A lightweight library that provides tools for organizing asynchronous code
—
Additional utility functions for promise creation, error handling, async scheduling, and deferred object management.
Create a fulfilled promise with the given value.
/**
* Create promise resolved with given value
* @param value - Value to resolve promise with (can be thenable)
* @param label - Optional string for debugging/tooling
* @returns Promise resolved with value
*/
function resolve(value?: any, label?: string): Promise;Usage Examples:
import { resolve } from "rsvp";
// Create immediately resolved promise
resolve("Hello World")
.then(value => console.log(value)); // "Hello World"
// Resolve with complex object
resolve({ user: "John", id: 123 })
.then(data => console.log(data.user)); // "John"
// Resolve with another promise (promise assimilation)
const nestedPromise = resolve("nested");
resolve(nestedPromise)
.then(value => console.log(value)); // "nested"
// Useful for converting values to promises in chains
function processData(input) {
if (typeof input === 'string') {
return resolve(input.toUpperCase());
}
return fetchData(input); // returns promise
}Create a rejected promise with the given reason.
/**
* Create promise rejected with given reason
* @param reason - Reason for rejection (typically Error object)
* @param label - Optional string for debugging/tooling
* @returns Promise rejected with reason
*/
function reject(reason?: any, label?: string): Promise;Usage Examples:
import { reject } from "rsvp";
// Create immediately rejected promise
reject(new Error("Something went wrong"))
.catch(error => console.error(error.message));
// Useful for validation flows
function validateUser(user) {
if (!user.email) {
return reject(new Error("Email is required"));
}
return resolve(user);
}
// Error propagation in promise chains
function processRequest(request) {
if (!request.isValid) {
return reject(new Error("Invalid request"));
}
return handleRequest(request);
}Create a deferred object with manual control over promise resolution.
/**
* Create deferred object for manual promise control
* @param label - Optional string for debugging/tooling
* @returns Object with promise, resolve, and reject properties
*/
function defer(label?: string): DeferredObject;
interface DeferredObject {
promise: Promise;
resolve: Function;
reject: Function;
}Usage Examples:
import { defer } from "rsvp";
// Basic deferred usage
const deferred = defer();
// Resolve later
setTimeout(() => {
deferred.resolve("Delayed result");
}, 1000);
deferred.promise.then(value => {
console.log(value); // "Delayed result" (after 1 second)
});
// Conditional resolution
const conditionalDeferred = defer();
if (someCondition) {
conditionalDeferred.resolve("Success");
} else {
conditionalDeferred.reject(new Error("Failed"));
}
// Useful for converting callback APIs
function promisifyCallback(callback) {
const deferred = defer();
callback((error, result) => {
if (error) {
deferred.reject(error);
} else {
deferred.resolve(result);
}
});
return deferred.promise;
}Rethrow an error on the next tick for debugging while maintaining promise chain.
/**
* Rethrow error on next tick for debugging
* @param reason - Error to rethrow
* @throws Error both immediately and asynchronously
*/
function rethrow(reason: any): void;Usage Examples:
import { rethrow } from "rsvp";
// Use in promise chains for debugging
promise
.catch(rethrow) // Throws error to console/debugger
.then(() => {
// This won't run due to rethrow
}, (error) => {
// This will handle the error normally
console.log("Handled error:", error);
});
// Debugging unhandled promise rejections
function createRiskyPromise() {
return new Promise((resolve, reject) => {
// Simulate error
reject(new Error("Something bad happened"));
});
}
createRiskyPromise()
.catch(rethrow); // Error will appear in console and be re-thrown
// Note: rethrow both throws immediately and schedules async throw
// This allows both immediate handling and console debuggingSchedule callback to run as soon as possible using the best available method.
/**
* Schedule callback to run ASAP using optimal platform method
* @param callback - Function to execute
* @param arg - Argument to pass to callback
*/
function asap(callback: Function, arg?: any): void;Usage Examples:
import { asap } from "rsvp";
// Schedule immediate callback
asap(function(message) {
console.log(message);
}, "Hello from next tick");
// Useful for breaking out of synchronous execution
function breakSyncChain(value) {
asap(function() {
processValue(value);
});
}
// Custom async pattern
function deferredLog(message) {
asap(console.log, message);
}
deferredLog("This will log asynchronously");
console.log("This logs first");Alias for the configured async scheduling function.
/**
* Execute callback using configured async scheduler
* @param callback - Function to execute
* @param arg - Argument to pass to callback
*/
function async(callback: Function, arg?: any): void;Usage Examples:
import { async, configure } from "rsvp";
// Uses the configured async function (same as asap by default)
async(function(data) {
console.log("Async execution:", data);
}, { key: "value" });
// Can be customized via configuration
configure('async', function(callback, arg) {
// Custom scheduling logic
requestAnimationFrame(() => callback(arg));
});
// Now async() uses requestAnimationFrame
async(function() {
console.log("Scheduled with requestAnimationFrame");
});Deprecated alias for resolve, maintained for backwards compatibility.
/**
* @deprecated Use resolve() instead
* Create promise resolved with given value
* @param value - Value to resolve promise with
* @param label - Optional string for debugging/tooling
* @returns Promise resolved with value
*/
const cast: Function; // Same as resolveUsage (not recommended for new code):
import { cast } from "rsvp";
// Deprecated - use resolve() instead
cast("value").then(console.log);
// Preferred
import { resolve } from "rsvp";
resolve("value").then(console.log);asap uses the best available method for each platform:
process.nextTick (or setImmediate for Node 0.10.x)MutationObserverMessageChannelvertx.runOnLoop or vertx.runOnContextsetTimeoutimport { resolve, reject } from "rsvp";
function syncToAsync(syncFunction, input) {
try {
const result = syncFunction(input);
return resolve(result);
} catch (error) {
return reject(error);
}
}
// Usage
syncToAsync(JSON.parse, '{"valid": "json"}')
.then(parsed => console.log(parsed))
.catch(error => console.error("Parse failed:", error));import { defer } from "rsvp";
function waitForEvent(emitter, eventName, timeout = 5000) {
const deferred = defer();
const cleanup = () => {
emitter.removeListener(eventName, onEvent);
clearTimeout(timer);
};
const onEvent = (data) => {
cleanup();
deferred.resolve(data);
};
const timer = setTimeout(() => {
cleanup();
deferred.reject(new Error(`Timeout waiting for ${eventName}`));
}, timeout);
emitter.on(eventName, onEvent);
return deferred.promise;
}
// Usage
waitForEvent(eventEmitter, 'data', 3000)
.then(data => console.log("Received:", data))
.catch(error => console.error("Event timeout:", error));import { rethrow } from "rsvp";
// Enhanced rethrow with context
function debugRethrow(context) {
return function(error) {
console.error(`Error in ${context}:`, error);
return rethrow(error);
};
}
// Usage
fetchUserData(userId)
.catch(debugRethrow('user data fetch'))
.then(processUser)
.catch(debugRethrow('user processing'));Install with Tessl CLI
npx tessl i tessl/npm-rsvp