or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-thunkify

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

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/thunkify@2.1.x

To install, run

npx @tessl/cli install tessl/npm-thunkify@2.1.0

index.mddocs/

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