or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-call-me-maybe

Let your JS API users either give you a callback or receive a promise

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/call-me-maybe@1.0.x

To install, run

npx @tessl/cli install tessl/npm-call-me-maybe@1.0.0

index.mddocs/

Call Me Maybe

Call Me Maybe enables JavaScript APIs to support both callback and promise-based patterns simultaneously. It allows library authors to write promise-based code while automatically providing callback support for users who prefer the traditional error-first callback pattern.

Package Information

  • Package Name: call-me-maybe
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install call-me-maybe

Core Imports

const maybe = require("call-me-maybe");

ES6 Modules (with bundlers or Node.js ES module support):

import maybe from "call-me-maybe";

Basic Usage

const maybe = require("call-me-maybe");

// Use in your API function
function asyncFunc(cb) {
  return maybe(cb, new Promise((resolve, reject) => {
    // Your async logic here
    setTimeout(() => resolve("result"), 100);
  }));
}

// Users can call with callback
asyncFunc((err, result) => {
  if (err) console.error(err);
  else console.log(result); // "result"
});

// Or without callback to get promise
asyncFunc()
  .then(result => console.log(result)) // "result"
  .catch(err => console.error(err));

Capabilities

Dual Interface Function

The core functionality that enables APIs to support both callback and promise patterns.

/**
 * Provides dual callback/promise interface for async functions
 * @param {Function|null|undefined} cb - Optional error-first callback function
 * @param {Promise} promise - Promise to handle
 * @returns {undefined|Promise} Returns undefined when callback provided, otherwise returns the promise
 */
function maybe(cb, promise);

Behavior:

  • If cb is truthy: Executes the promise and calls the callback with error-first parameters
    • On promise fulfillment: cb(null, result)
    • On promise rejection: cb(err)
    • Returns undefined
  • If cb is falsy (null, undefined, false, etc.): Returns the original promise directly

Usage Examples:

Callback pattern:

const maybe = require("call-me-maybe");

function fetchData(cb) {
  return maybe(cb, fetch("/api/data").then(res => res.json()));
}

// With callback
fetchData((err, data) => {
  if (err) {
    console.error("Error:", err);
  } else {
    console.log("Data:", data);
  }
});

Promise pattern:

// Without callback - returns promise
fetchData()
  .then(data => console.log("Data:", data))
  .catch(err => console.error("Error:", err));

// Or with async/await
try {
  const data = await fetchData();
  console.log("Data:", data);
} catch (err) {
  console.error("Error:", err);
}

Complex example with error handling:

function processFile(filename, cb) {
  const filePromise = fs.promises.readFile(filename, 'utf8')
    .then(content => content.toUpperCase())
    .then(processed => ({ filename, content: processed }));
  
  return maybe(cb, filePromise);
}

// Callback style with error handling
processFile('data.txt', (err, result) => {
  if (err) {
    if (err.code === 'ENOENT') {
      console.log('File not found');
    } else {
      console.error('Unexpected error:', err);
    }
  } else {
    console.log(`Processed ${result.filename}: ${result.content}`);
  }
});

// Promise style
processFile('data.txt')
  .then(result => console.log(`Processed ${result.filename}: ${result.content}`))
  .catch(err => {
    if (err.code === 'ENOENT') {
      console.log('File not found');
    } else {
      console.error('Unexpected error:', err);
    }
  });

Implementation Details

Async Scheduling

Call Me Maybe uses intelligent async scheduling to ensure callbacks are called asynchronously, preventing potential issues with synchronous callback execution:

  • Uses process.nextTick in Node.js environments
  • Falls back to setImmediate if available (browser with setImmediate polyfill)
  • Falls back to setTimeout(fn, 0) as final option

This ensures consistent asynchronous behavior across all environments.

Error Handling

  • Callback errors are passed as the first parameter following Node.js error-first convention
  • Promise rejections are automatically converted to callback errors
  • Exceptions thrown within callbacks are allowed to bubble up as uncaught exceptions
  • When using callbacks, the function always returns undefined regardless of promise state

Environment Compatibility

  • Node.js: Full support with optimal process.nextTick scheduling
  • Browsers: Full support with fallback scheduling mechanisms
  • CommonJS: Native support via require()
  • ES6 Modules: Support via import statement
  • Zero Dependencies: No external dependencies required