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
Comprehensive Node.js callback integration for converting existing callback-based APIs to promises and integrating with the Node.js ecosystem.
Converts Node.js callback-style functions to promise-returning functions.
/**
* Wraps Node-style callback function to return promises
* @param callback - Node.js callback function (error, result) => void
* @param pattern - Optional parameter processing pattern
* @returns Promise-returning version of the function
*/
function Q.denodeify(callback, pattern);Usage Examples:
const Q = require("q");
const fs = require("fs");
// Convert filesystem functions
const readFile = Q.denodeify(fs.readFile);
const writeFile = Q.denodeify(fs.writeFile);
const stat = Q.denodeify(fs.stat);
// Use converted functions
readFile("package.json", "utf8")
.then(data => JSON.parse(data))
.then(json => console.log("Package name:", json.name))
.catch(error => console.error("Read error:", error));
// Convert custom callback functions
function oldStyleFunction(param1, param2, callback) {
setTimeout(() => {
if (param1 && param2) {
callback(null, param1 + param2);
} else {
callback(new Error("Invalid parameters"));
}
}, 100);
}
const newStyleFunction = Q.denodeify(oldStyleFunction);
newStyleFunction("Hello", " World")
.then(result => console.log(result)) // "Hello World"
.catch(error => console.error(error));
// Convert with pattern (for special cases)
const execFile = Q.denodeify(require("child_process").execFile);
execFile("ls", ["-la"])
.then(stdout => console.log(stdout))
.catch(error => console.error("Command failed:", error));Calls Node.js style methods on objects and returns promises.
/**
* Calls Node-style method and returns promise
* @param object - Object containing the method
* @param name - Method name to call
* @param ...args - Arguments to pass to method
* @returns Promise for method result
*/
function Q.ninvoke(object, name, ...args);
/**
* Calls Node-style method on fulfilled object
* @param name - Method name to call
* @param ...args - Arguments to pass to method
* @returns Promise for method result
*/
promise.ninvoke(name, ...args);Usage Examples:
const Q = require("q");
const fs = require("fs");
// Static method invocation
Q.ninvoke(fs, "readFile", "config.json", "utf8")
.then(data => JSON.parse(data))
.then(config => console.log("Config loaded:", config))
.catch(error => console.error("Config load failed:", error));
// Instance method invocation with promise of object
const redisClient = getRedisClient();
Q.resolve(redisClient)
.ninvoke("get", "user:123")
.then(userData => {
if (userData) {
return JSON.parse(userData);
}
throw new Error("User not found");
})
.then(user => console.log("User:", user))
.catch(error => console.error("Redis error:", error));
// Chaining method calls
const dbConnection = connectToDatabase();
Q.resolve(dbConnection)
.ninvoke("query", "SELECT * FROM users WHERE active = ?", [true])
.then(users => {
console.log(`Found ${users.length} active users`);
return Q.ninvoke(dbConnection, "query",
"UPDATE users SET last_seen = NOW() WHERE active = ?", [true]);
})
.then(result => console.log("Updated timestamps"))
.catch(error => console.error("Database error:", error));Converts promises back to Node.js callback style for integration with callback-expecting code.
/**
* Converts promise to Node-style callback pattern
* @param nodeback - Node.js style callback function (error, result) => void
* @returns void (calls nodeback with result)
*/
promise.nodeify(nodeback);Usage Examples:
const Q = require("q");
// Convert promise to callback for legacy API
function legacyFunction(callback) {
const promise = fetchUserData()
.then(user => processUser(user))
.then(result => ({ success: true, data: result }))
.catch(error => ({ success: false, error: error.message }));
promise.nodeify(callback);
}
// Use with traditional callback patterns
legacyFunction((error, result) => {
if (error) {
console.error("Operation failed:", error);
} else {
console.log("Operation result:", result);
}
});
// Integration with Express.js middleware
function promiseMiddleware(req, res, next) {
authenticateUser(req.headers.authorization)
.then(user => {
req.user = user;
return user;
})
.nodeify(next); // Calls next() on success, next(error) on failure
}
// Callback-style wrapper for promise-based function
function fetchDataCallback(userId, callback) {
Q.resolve(userId)
.then(id => validateUserId(id))
.then(id => fetchFromDatabase(id))
.then(data => processData(data))
.nodeify(callback);
}
// Using the callback wrapper
fetchDataCallback("user123", (error, data) => {
if (error) {
console.error("Fetch failed:", error);
} else {
console.log("Data received:", data);
}
});Creating Node.js compatible resolvers from deferred objects.
/**
* Creates Node-style callback resolver from deferred
* @param unpack - Optional flag to unpack single-element arrays
* @returns Node.js callback function
*/
deferred.makeNodeResolver(unpack);Usage Examples:
const Q = require("q");
const fs = require("fs");
// Use deferred with Node.js APIs
function readFilePromise(filename) {
const deferred = Q.defer();
const nodeCallback = deferred.makeNodeResolver();
fs.readFile(filename, "utf8", nodeCallback);
return deferred.promise;
}
// With unpacking for single results
function statFilePromise(filename) {
const deferred = Q.defer();
const nodeCallback = deferred.makeNodeResolver(true);
fs.stat(filename, nodeCallback);
return deferred.promise;
}
// Complex integration example
function executeQuery(sql, params) {
const deferred = Q.defer();
const nodeCallback = deferred.makeNodeResolver();
database.query(sql, params, (error, results, fields) => {
if (error) {
nodeCallback(error);
} else {
nodeCallback(null, { results, fields });
}
});
return deferred.promise;
}
// Using the promise-wrapped function
executeQuery("SELECT * FROM users WHERE id = ?", [123])
.then(({ results, fields }) => {
console.log("Query results:", results);
console.log("Field info:", fields);
})
.catch(error => console.error("Query failed:", error));const Q = require("q");
const fs = require("fs");
const path = require("path");
// Create promise-based fs operations
const readFile = Q.denodeify(fs.readFile);
const writeFile = Q.denodeify(fs.writeFile);
const readdir = Q.denodeify(fs.readdir);
const stat = Q.denodeify(fs.stat);
// Complex file operations
function processDirectory(dirPath) {
return readdir(dirPath)
.then(files => {
const filePromises = files.map(file => {
const fullPath = path.join(dirPath, file);
return stat(fullPath)
.then(stats => ({ name: file, path: fullPath, stats }));
});
return Q.all(filePromises);
})
.then(fileInfos => {
const textFiles = fileInfos.filter(info =>
info.stats.isFile() && path.extname(info.name) === ".txt"
);
return textFiles;
});
}const Q = require("q");
// Wrap database connection methods
function createDbWrapper(connection) {
return {
query: Q.denodeify(connection.query.bind(connection)),
beginTransaction: Q.denodeify(connection.beginTransaction.bind(connection)),
commit: Q.denodeify(connection.commit.bind(connection)),
rollback: Q.denodeify(connection.rollback.bind(connection))
};
}
// Use wrapped database
const db = createDbWrapper(mysqlConnection);
function updateUserWithTransaction(userId, userData) {
return db.beginTransaction()
.then(() => db.query("UPDATE users SET ? WHERE id = ?", [userData, userId]))
.then(result => {
if (result.affectedRows === 0) {
throw new Error("User not found");
}
return db.commit();
})
.catch(error => {
return db.rollback().then(() => {
throw error;
});
});
}Install with Tessl CLI
npx tessl i tessl/npm-q