{"id":17344,"library":"real-cancellable-promise","title":"Real Cancellable Promise","description":"`real-cancellable-promise` is a robust and lightweight library offering a cancellable Promise implementation for JavaScript and TypeScript. Unlike many other approaches that merely prevent callbacks from executing, this library focuses on propagating cancellation signals to the underlying asynchronous operations, such as network requests made with `fetch`, `axios`, or `jQuery.ajax`, thereby releasing resources and truly aborting tasks. It boasts zero dependencies and a minimal footprint, under 1 kB minified and gzipped. The current stable version is 1.2.3, with ongoing active maintenance reflected in its consistent bug fix releases. Key differentiators include its explicit support for 'real' cancellation and its compatibility with popular ecosystems like React (solving issues like `setState` after unmount and handling variable query parameters) and `react-query`'s cancellation features out-of-the-box. It supports modern browsers (excluding Internet Explorer) and Node.js 14+ (with `AbortController` functionality requiring Node 15+).","status":"active","version":"1.2.3","language":"javascript","source_language":"en","source_url":"https://github.com/srmagura/real-cancellable-promise","tags":["javascript","promise","cancelable","cancellable","react","typescript"],"install":[{"cmd":"npm install real-cancellable-promise","lang":"bash","label":"npm"},{"cmd":"yarn add real-cancellable-promise","lang":"bash","label":"yarn"},{"cmd":"pnpm add real-cancellable-promise","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"ESM imports are preferred. CommonJS require() works but named exports must be accessed as properties on the imported object.","wrong":"const CancellablePromise = require('real-cancellable-promise').CancellablePromise;","symbol":"CancellablePromise","correct":"import { CancellablePromise } from 'real-cancellable-promise';"},{"note":"This utility function, useful for composing cancellable operations, is a named export, not a default export.","wrong":"import buildCancellablePromise from 'real-cancellable-promise';","symbol":"buildCancellablePromise","correct":"import { buildCancellablePromise } from 'real-cancellable-promise';"},{"note":"The Cancellation error object is typically imported to differentiate it from other promise rejections when catching errors.","wrong":"const { Cancellation } = require('real-cancellable-promise');","symbol":"Cancellation","correct":"import { Cancellation } from 'real-cancellable-promise';"}],"quickstart":{"code":"import { CancellablePromise, Cancellation } from 'real-cancellable-promise';\n\ninterface Post { id: number; title: string; body: string; }\n\n// Simulate an API call with AbortController for real cancellation\nfunction fetchPostWithCancellation(postId: number): CancellablePromise<Post> {\n  const abortController = new AbortController();\n  const signal = abortController.signal;\n\n  const promise = fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`, { signal })\n    .then(response => {\n      if (!response.ok) {\n        throw new Error(`HTTP error! Status: ${response.status}`);\n      }\n      return response.json();\n    });\n\n  return new CancellablePromise(\n    promise,\n    () => {\n      abortController.abort(new Cancellation(`Request for post ${postId} was cancelled.`));\n    }\n  );\n}\n\nasync function runExample() {\n  console.log('Fetching post 1...');\n  const cancellableFetch = fetchPostWithCancellation(1);\n\n  try {\n    // Start the fetch but cancel it after a short delay\n    const timeoutId = setTimeout(() => {\n      console.log('Attempting to cancel fetch for post 1...');\n      cancellableFetch.cancel();\n    }, 50);\n\n    const post = await cancellableFetch;\n    clearTimeout(timeoutId);\n    console.log('Fetched post:', post.title);\n  } catch (error) {\n    if (error instanceof Cancellation) {\n      console.log('Fetch for post 1 was successfully cancelled:', error.message);\n    } else {\n      console.error('Fetch for post 1 failed:', error);\n    }\n  }\n\n  // Demonstrate a successful fetch\n  console.log('\\nFetching post 2...');\n  const successfulFetch = fetchPostWithCancellation(2);\n  try {\n    const post = await successfulFetch;\n    console.log('Successfully fetched post 2:', post.title);\n  } catch (error) {\n    console.error('Fetch for post 2 failed:', error);\n  }\n}\n\nrunExample();\n","lang":"typescript","description":"This example demonstrates how to create a `CancellablePromise` using `AbortController` for an HTTP `fetch` request, initiate the request, and then cancel it, explicitly handling the `Cancellation` error. It also shows a successful fetch for comparison."},"warnings":[{"fix":"Upgrade to version 1.2.3 or higher to ensure `Cancellation` propagates correctly through promise chains.","message":"In versions prior to 1.2.3, a `Cancellation` error might not be thrown as expected within a `.then()` chain if the initial promise had already resolved, leading to unhandled promise rejections or unexpected behavior.","severity":"gotcha","affected_versions":"<1.2.3"},{"fix":"Update to version 1.2.1 or newer to resolve the memory leak issue, especially for applications involving numerous or long-lived cancellable operations.","message":"Version 1.2.1 fixed a memory leak that occurred when `buildCancellablePromise` was used to create very long-running tasks, potentially impacting application stability over time.","severity":"gotcha","affected_versions":"<1.2.1"},{"fix":"Ensure your build tooling (e.g., Webpack, Rollup) or Node.js environment is configured to correctly handle ES module resolution if you experience issues with imports. Node.js 14+ is supported, with `AbortController` usage in Node 15+.","message":"The package started publishing an ES module alongside a CommonJS module in v1.1.0. While bundlers and Node.js generally pick the correct format, older tools or specific configurations might encounter module resolution issues.","severity":"gotcha","affected_versions":">=1.1.0"},{"fix":"Ensure your `cancel` callback function passed to the `CancellablePromise` constructor calls `reject(new Cancellation(...))` or `abortController.abort(new Cancellation(...))` to properly signal cancellation.","message":"The `CancellablePromise` constructor requires the `cancel` function to explicitly cause the wrapped promise to reject with a `Cancellation` object. Simply providing an empty function or a function that doesn't reject will not achieve 'real' cancellation.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Upgrade to version 1.1.1 or higher to benefit from improved type compatibility, allowing `CancellablePromise` instances to be used where `Promise` instances are expected.","message":"Prior to version 1.1.1, `CancellablePromise<T>` was not directly assignable to `Promise<T>` in TypeScript, leading to type errors when integrating with APIs expecting standard Promises.","severity":"gotcha","affected_versions":"<1.1.1"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Ensure you are creating an instance of `CancellablePromise` (e.g., `new CancellablePromise(...)`) and that you have correctly imported `CancellablePromise` from the package. Double-check that you are not mistakenly assigning a standard Promise to your `cancellablePromise` variable.","cause":"This usually happens when you try to call `.cancel()` on a regular `Promise` instance or on a `CancellablePromise` that was not correctly constructed or imported.","error":"TypeError: cancellablePromise.cancel is not a function"},{"fix":"Add `import { Cancellation } from 'real-cancellable-promise';` (for ESM) or `const { Cancellation } = require('real-cancellable-promise');` (for CJS) at the top of your file.","cause":"The `Cancellation` error class is a named export and must be explicitly imported before use.","error":"ReferenceError: Cancellation is not defined"},{"fix":"Add a `.catch()` block to your promise chain to handle `Cancellation` errors. It's often good practice to specifically check `if (error instanceof Cancellation)` to handle cancellations differently from other errors.","cause":"A `CancellablePromise` was cancelled, but the resulting `Cancellation` error was not caught by a `.catch()` handler in the promise chain.","error":"Unhandled Promise Rejection: Cancellation: Request for post 1 was cancelled."},{"fix":"If in a CommonJS context, use `const { CancellablePromise } = require('real-cancellable-promise');`. If using a bundler, ensure it's configured to correctly transpile or resolve ESM. Ensure your Node.js version is compatible with the module format you are using (Node.js 14+ is generally supported, but `import` syntax might need specific configuration in older Node.js environments).","cause":"This error typically occurs in a CommonJS environment (or an older Node.js version/bundler) when attempting to use ES module `import { NamedExport } from 'module';` syntax, and the module isn't correctly transpiled or resolved as CJS.","error":"SyntaxError: Named export 'CancellablePromise' not found. The requested module 'real-cancellable-promise' does not provide an export named 'CancellablePromise'"}],"ecosystem":"npm","meta_description":null}