Turn callbacks, arrays, generators, generator functions, and promises into a thunk
npx @tessl/cli install tessl/npm-thunkify@2.1.0Thunkify converts regular Node.js callback-based functions into thunks, which are functions that accept a callback as their only parameter. This transformation is particularly useful for generator-based flow control systems like co, enabling seamless integration of callback-based APIs with modern async/await patterns.
npm install thunkifyconst thunkify = require('thunkify');For ES modules:
import thunkify from 'thunkify';const thunkify = require('thunkify');
const fs = require('fs');
// Convert fs.readFile to a thunk
const readFile = thunkify(fs.readFile);
// Use the thunked function
readFile('package.json', 'utf8')(function(err, data) {
if (err) throw err;
console.log(data);
});
// Works with generator-based flow control
function* readFiles() {
const data1 = yield readFile('file1.txt', 'utf8');
const data2 = yield readFile('file2.txt', 'utf8');
return [data1, data2];
}Converts callback-based functions into thunks for use with generator-based flow control.
/**
* Wrap a regular callback function as a thunk
* @param {Function} fn - A callback-based function to convert
* @returns {Function} A thunk function that accepts arguments and returns a function expecting a callback
* @throws {AssertionError} If fn is not a function
*/
function thunkify(fn): (...args: any[]) => (callback: (err?: Error, ...results: any[]) => void) => void;The thunkify function:
this context when used with object methodsUsage Examples:
const thunkify = require('thunkify');
const fs = require('fs');
// Basic function thunking
const readFile = thunkify(fs.readFile);
readFile('package.json', 'utf8')(function(err, data) {
console.log(data);
});
// Method thunking with context preservation
const user = {
name: 'Alice',
load: thunkify(function(callback) {
// 'this' refers to the user object
callback(null, this.name);
})
};
user.load()(function(err, name) {
console.log(name); // 'Alice'
});
// Error handling - synchronous errors are caught
const faultyFn = thunkify(function(callback) {
throw new Error('Something went wrong');
});
faultyFn()(function(err) {
console.log(err.message); // 'Something went wrong'
});
// Multiple return values are preserved
const multiReturn = thunkify(function(a, b, callback) {
callback(null, a + b, a * b);
});
multiReturn(5, 3)(function(err, sum, product) {
console.log(sum); // 8
console.log(product); // 15
});Thunkify provides comprehensive error handling:
AssertionError if the input is not a functionconst thunkify = require('thunkify');
// Input validation error
try {
thunkify('not a function');
} catch (err) {
console.log(err.name); // 'AssertionError'
}
// Synchronous error handling
const errorFn = thunkify(function(callback) {
throw new Error('Sync error');
});
errorFn()(function(err) {
console.log(err.message); // 'Sync error'
});Thunkify is designed to work seamlessly with generator-based libraries like co:
const co = require('co');
const thunkify = require('thunkify');
const fs = require('fs');
const readFile = thunkify(fs.readFile);
const writeFile = thunkify(fs.writeFile);
co(function* () {
const data = yield readFile('input.txt', 'utf8');
const processed = data.toUpperCase();
yield writeFile('output.txt', processed, 'utf8');
console.log('File processing complete');
}).catch(console.error);While primarily designed for generators, thunked functions can be adapted for async/await:
const thunkify = require('thunkify');
const { promisify } = require('util');
// Convert thunk to promise
function thunkToPromise(thunk) {
return new Promise((resolve, reject) => {
thunk((err, ...args) => {
if (err) reject(err);
else resolve(args.length === 1 ? args[0] : args);
});
});
}
// Usage with async/await
async function example() {
const readFile = thunkify(fs.readFile);
const data = await thunkToPromise(readFile('package.json', 'utf8'));
console.log(data);
}