{"id":11969,"library":"run-async","title":"Unified Async/Sync Function Execution","description":"run-async is a utility method designed to normalize the execution of functions that can operate synchronously, asynchronously via a `this.async()` callback, or by returning a Promise. This library is particularly useful for authors of middleware or plugins that need to accept user-provided functions with varying asynchronous patterns, ensuring a consistent execution flow. The current stable version is 4.0.6, and the project demonstrates an active maintenance cadence, addressing dependency issues and enhancing functionality across major versions. A key differentiator is its ability to abstract away the underlying async mechanism, providing a single interface, and its current status as a dependency-free package since version 2.4.1, which improves reliability and reduces supply chain risks.","status":"active","version":"4.0.6","language":"javascript","source_language":"en","source_url":"https://github.com/SBoudrias/run-async","tags":["javascript","flow","flow-control","async","typescript"],"install":[{"cmd":"npm install run-async","lang":"bash","label":"npm"},{"cmd":"yarn add run-async","lang":"bash","label":"yarn"},{"cmd":"pnpm add run-async","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"While CommonJS `require` is shown in the README, modern Node.js and TypeScript projects should use ESM imports.","wrong":"const runAsync = require('run-async');","symbol":"runAsync","correct":"import { runAsync } from 'run-async';"},{"note":"`cb` is a property of the main `runAsync` export, not a separate named export.","wrong":"import { cb } from 'run-async';","symbol":"runAsync.cb","correct":"import { runAsync } from 'run-async'; runAsync.cb(...);"},{"note":"For type-checking in TypeScript, import the `RunAsync` interface or similar utility types.","symbol":"RunAsync function types","correct":"import type { RunAsync } from 'run-async';"}],"quickstart":{"code":"import { runAsync } from 'run-async';\n\n// A helper to demonstrate how runAsync normalizes different function types\nconst printAfter = async (func: Function) => {\n  const cb = (err: Error | null, returnValue: unknown) => {\n    if (err) {\n      console.error('Error:', err);\n      return;\n    }\n    console.log(returnValue);\n  };\n\n  // Execute the function using runAsync, passing a callback\n  // runAsync returns a function that takes arguments for func\n  try {\n    const result = await runAsync(func, cb)();\n    // If func returns a Promise, runAsync resolves it. The callback also fires.\n    // We'll catch the potential Promise resolution here.\n    // The callback provided to runAsync will still be called.\n  } catch (error) {\n    console.error('Caught an error from runAsync execution:', error);\n  }\n};\n\nconsole.log('--- Using this.async ---');\nprintAfter(function (this: any) {\n  const done = this.async();\n  setTimeout(() => {\n    done(null, 'done running with callback');\n  }, 10);\n});\n\nconsole.log('\\n--- Returning a Promise ---');\nprintAfter(function () {\n  return new Promise(resolve => {\n    setTimeout(() => resolve('done running with promises'), 5);\n  });\n});\n\nconsole.log('\\n--- Synchronous function ---');\nprintAfter(function () {\n  return 'done running sync function';\n});\n\n// Example using runAsync.cb for Node.js callback style\nconsole.log('\\n--- Using runAsync.cb (Node.js callback style) ---');\nrunAsync.cb(\n  (a: number, b: number, cb: (err: Error | null, result: number) => void) => {\n    setTimeout(() => cb(null, a + b), 20);\n  },\n  (err: Error | null, result: number) => {\n    if (err) console.error('Error with runAsync.cb:', err);\n    else console.log(`runAsync.cb result: ${result}`);\n  }\n)(5, 7);\n","lang":"typescript","description":"Demonstrates how to use `runAsync` to execute functions that use `this.async()`, return a Promise, or return a synchronous value. Also includes an example of `runAsync.cb` for Node.js callback-style functions."},"warnings":[{"fix":"Migrate your usage to consume the returned Promise (e.g., `runAsync(func)(args).then(cb)`) or ensure your callback handling is compatible with both Promise-based and traditional callback flows.","message":"Version 2.0.0 changed the `runAsync` signature. If your Node.js version supports native Promises, `runAsync` will now return a Promise, altering how it's consumed compared to earlier versions that exclusively used callbacks.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Ensure that any function passed to `runAsync.cb` explicitly defines all its parameters, including the final callback argument.","message":"The `runAsync.cb` function, introduced in v2.1.0, requires the wrapped function to have a fixed number of parameters. Variable argument functions or functions with `arguments` objects may not behave as expected.","severity":"breaking","affected_versions":">=2.1.0"},{"fix":"Be aware that `runAsync` will always return a Promise for consistent behavior across Node.js versions, which might slightly change execution flow compared to pre-2.2.0 versions on older Node.js.","message":"Prior to v2.2.0, Promise polyfill behavior was conditional. Since v2.2.0, `runAsync` consistently returns a Promise, relying on the 'Pinkie' polyfill if native Promises are not available in the Node.js environment.","severity":"gotcha","affected_versions":">=2.2.0"},{"fix":"Upgrade `run-async` to version 2.4.1 or higher to remove the `is-promise` dependency and ensure a more stable, dependency-free experience.","message":"The `is-promise` dependency was removed in v2.4.1 due to issues with the upstream package, making `run-async` dependency-free. Older versions might have experienced unexpected behavior or issues related to this dependency.","severity":"gotcha","affected_versions":"<2.4.1"},{"fix":"Upgrade your Node.js runtime to a supported version (e.g., 0.12 or higher as per package.json engines) to ensure native Promise support or proper polyfill handling by `run-async`.","message":"The Node.js 0.10 Promise polyfill was removed in v2.3.0. Users on very old Node.js 0.10 environments might experience Promise-related issues without the polyfill.","severity":"gotcha","affected_versions":">=2.3.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure `runAsync` is called such that the wrapped function's `this` context is correctly bound or provided by `run-async` itself. Avoid using arrow functions for the wrapped function if you intend to use `this.async()`, as arrow functions lexically bind `this`.","cause":"The function passed to `runAsync` is not being called with the correct `this` context, which typically provides the `async` method.","error":"TypeError: this.async is not a function"},{"fix":"Review your asynchronous logic to ensure that `done()`, `resolve()`, or `reject()` are called exactly once per `runAsync` invocation, even in error scenarios. Add guards to prevent multiple calls.","cause":"This error typically occurs when the `done()` callback (from `this.async()`) or a Promise's `resolve`/`reject` function is invoked more than once within the wrapped function.","error":"Error: Callback was already called."}],"ecosystem":"npm"}