A comprehensive promise library implementing CommonJS Promises/A,B,D specifications for JavaScript
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Function wrappers and utilities for integrating promises with functional programming patterns, including async/generator support and promise-based functional composition.
Utilities for wrapping regular functions to work seamlessly with promises.
/**
* Wraps function to return promises
* @param wrapped - Function to wrap for promise compatibility
* @returns Function that returns promises
*/
function Q.function(wrapped);
/**
* Decorator ensuring promise arguments and return value
* @param callback - Function to wrap with promise handling
* @returns Function that handles promise arguments and returns promises
*/
function Q.promised(callback);Usage Examples:
const Q = require("q");
// Wrap regular function to return promises
const syncAdd = (a, b) => a + b;
const asyncAdd = Q.function(syncAdd);
asyncAdd(5, 3)
.then(result => console.log("Result:", result)) // 8
.catch(error => console.error(error));
// Wrap function that may throw
const riskyFunction = (data) => {
if (!data) throw new Error("No data provided");
return data.toUpperCase();
};
const safeRiskyFunction = Q.function(riskyFunction);
safeRiskyFunction("hello")
.then(result => console.log(result)) // "HELLO"
.catch(error => console.error(error));
safeRiskyFunction(null)
.catch(error => console.error("Caught:", error.message));
// Q.promised for promise-aware functions
const promisedProcessor = Q.promised((data, config) => {
// Both data and config can be promises or values
return `Processed: ${data} with ${config.mode}`;
});
// Use with mixed promise/value arguments
promisedProcessor(
Q.delay("user data", 100),
{ mode: "strict" }
).then(result => console.log(result));
// Chain with other promise operations
const processUser = Q.promised((user, settings) => {
return {
id: user.id,
name: user.name.toUpperCase(),
theme: settings.theme
};
});
fetchUser(123)
.then(user => processUser(user, getSettings()))
.then(processedUser => console.log(processedUser));Functions for comparing and joining promise values.
/**
* Resolves to value if both promises fulfill to same value
* @param x - First promise or value
* @param y - Second promise or value
* @returns Promise that resolves if both values are equal
*/
function Q.join(x, y);Usage Examples:
const Q = require("q");
// Join with identical values
Q.join(Q.resolve("same"), Q.resolve("same"))
.then(value => console.log("Both resolved to:", value))
.catch(() => console.log("Values were different"));
// Join with different values (will reject)
Q.join(Q.resolve("first"), Q.resolve("second"))
.then(value => console.log("Unexpected success:", value))
.catch(() => console.log("Values were different, as expected"));
// Real-world example: verify consistency
function verifyDataConsistency(primarySource, backupSource) {
return Q.join(
fetchDataFromPrimary(primarySource),
fetchDataFromBackup(backupSource)
).then(consistentData => {
console.log("Data is consistent:", consistentData);
return consistentData;
}).catch(error => {
console.warn("Data inconsistency detected, investigating...");
return investigateInconsistency(primarySource, backupSource);
});
}
// Permission verification
function verifyUserPermissions(userId, requiredRole) {
return Q.join(
fetchUserRole(userId),
Q.resolve(requiredRole)
).then(role => {
console.log(`User has required role: ${role}`);
return true;
}).catch(() => {
console.log("User does not have required permissions");
return false;
});
}Advanced support for ES6 generator functions and async patterns.
/**
* Decorator for generator functions to work with promises
* @param makeGenerator - Generator function that yields promises
* @returns Function that returns promise for generator completion
*/
function Q.async(makeGenerator);
/**
* Runs async generator immediately with error handling
* @param makeGenerator - Generator function to execute
* @returns Promise for generator completion result
*/
function Q.spawn(makeGenerator);Usage Examples:
const Q = require("q");
// Q.async for reusable async generators
const fetchUserProfile = Q.async(function* (userId) {
const user = yield fetchUser(userId);
const preferences = yield fetchUserPreferences(userId);
const activity = yield fetchUserActivity(userId);
return {
user,
preferences,
activity,
lastUpdated: new Date()
};
});
// Use the async function
fetchUserProfile(123)
.then(profile => console.log("Complete profile:", profile))
.catch(error => console.error("Profile fetch failed:", error));
// Q.spawn for immediate execution
Q.spawn(function* () {
try {
console.log("Starting data migration...");
const sourceData = yield connectToSourceDatabase();
const targetDb = yield connectToTargetDatabase();
const users = yield sourceData.query("SELECT * FROM users");
console.log(`Migrating ${users.length} users...`);
for (let user of users) {
yield targetDb.insert("users", transformUser(user));
console.log(`Migrated user: ${user.name}`);
}
yield sourceData.close();
yield targetDb.close();
console.log("Migration completed successfully");
} catch (error) {
console.error("Migration failed:", error);
throw error;
}
}).done();
// Complex async workflow
const processOrderWorkflow = Q.async(function* (orderId) {
const order = yield fetchOrder(orderId);
// Validate order
const validation = yield validateOrder(order);
if (!validation.valid) {
throw new Error(`Order validation failed: ${validation.errors.join(", ")}`);
}
// Process payment
const paymentResult = yield processPayment(order.payment);
if (!paymentResult.success) {
throw new Error(`Payment failed: ${paymentResult.error}`);
}
// Update inventory
yield updateInventory(order.items);
// Schedule shipping
const shipping = yield scheduleShipping(order);
// Send confirmations
yield Q.all([
sendCustomerConfirmation(order.customerId, order),
sendMerchantNotification(order.merchantId, order),
logOrderProcessing(orderId, "completed")
]);
return {
orderId,
status: "processed",
paymentId: paymentResult.transactionId,
shippingId: shipping.trackingNumber,
processedAt: new Date()
};
});
// Usage
processOrderWorkflow("order-123")
.then(result => console.log("Order processed:", result))
.catch(error => console.error("Order processing failed:", error));Advanced functional programming patterns with promises.
const Q = require("q");
// Promise-based map function
function promiseMap(array, mapper) {
const mappedPromises = array.map(item => Q.resolve(item).then(mapper));
return Q.all(mappedPromises);
}
// Promise-based filter function
function promiseFilter(array, predicate) {
const filterPromises = array.map(item =>
Q.resolve(item).then(predicate).then(passed => ({ item, passed }))
);
return Q.all(filterPromises).then(results =>
results.filter(result => result.passed).map(result => result.item)
);
}
// Promise-based reduce function
function promiseReduce(array, reducer, initialValue) {
return array.reduce((promise, item) => {
return promise.then(accumulator =>
Q.all([accumulator, item]).spread(reducer)
);
}, Q.resolve(initialValue));
}
// Usage examples
const numbers = [1, 2, 3, 4, 5];
// Map with async operation
promiseMap(numbers, num => Q.delay(num * 2, 50))
.then(doubled => console.log("Doubled:", doubled));
// Filter with async predicate
promiseFilter(numbers, num => Q.delay(num > 3, 10))
.then(filtered => console.log("Filtered:", filtered));
// Reduce with async reducer
promiseReduce(numbers, (acc, num) => Q.delay(acc + num, 10), 0)
.then(sum => console.log("Sum:", sum));Utilities for composing promise-based functions.
const Q = require("q");
// Function composition for promises
function composeAsync(...functions) {
return function(input) {
return functions.reduce((promise, fn) => {
return promise.then(fn);
}, Q.resolve(input));
};
}
// Pipeline for sequential processing
function pipeline(...stages) {
return function(input) {
return stages.reduce((promise, stage) => {
return promise.then(stage);
}, Q.resolve(input));
};
}
// Usage
const processData = composeAsync(
data => Q.delay(data.trim(), 10),
data => Q.delay(data.toUpperCase(), 10),
data => Q.delay(`Processed: ${data}`, 10)
);
processData(" hello world ")
.then(result => console.log(result)); // "Processed: HELLO WORLD"
// Data processing pipeline
const dataPipeline = pipeline(
data => validateInput(data),
data => enrichWithMetadata(data),
data => applyBusinessRules(data),
data => formatForOutput(data)
);
dataPipeline(rawData)
.then(processedData => console.log("Pipeline result:", processedData))
.catch(error => console.error("Pipeline failed:", error));Install with Tessl CLI
npx tessl i tessl/npm-q