CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-thunkify

Turn callbacks, arrays, generators, generator functions, and promises into a thunk

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

Thunkify

Thunkify 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.

Package Information

  • Package Name: thunkify
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install thunkify
  • License: MIT
  • Dependencies: None

Core Imports

const thunkify = require('thunkify');

For ES modules:

import thunkify from 'thunkify';

Basic Usage

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];
}

Capabilities

Function Conversion

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:

  • Input: Takes any callback-based function that follows Node.js callback conventions (error-first callback)
  • Output: Returns a thunk function that preserves all original arguments and context
  • Context Preservation: Maintains this context when used with object methods
  • Error Handling: Catches synchronous exceptions and forwards them to the callback
  • Callback Safety: Ensures the callback is only called once, ignoring subsequent calls
  • Argument Forwarding: Preserves all function arguments and callback results

Usage 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
});

Error Handling

Thunkify provides comprehensive error handling:

  • Input Validation: Throws AssertionError if the input is not a function
  • Synchronous Errors: Catches thrown exceptions and passes them to the callback
  • Callback Protection: Prevents multiple callback invocations, ignoring subsequent calls
  • Error Forwarding: Preserves the original error-first callback pattern
const 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'
});

Integration Patterns

Generator-based Flow Control

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);

Async/Await Compatibility

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);
}
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/thunkify@2.1.x
Publish Source
CLI
Badge
tessl/npm-thunkify badge