npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

p-abort

v0.2.1

Published

Abortable step-by-step operations

Readme

p-abort

Abortable step-by-step operations with automatic cleanup.

Installation

npm install p-abort
pnpm add p-abort
yarn add p-abort

Overview

p-abort provides a utility for creating abortable asynchronous operations that can be cleanly cancelled at any step. It's particularly useful for:

  • Long-running async operations that need cancellation support
  • Multi-step workflows where intermediate steps should be skippable
  • Resource cleanup when operations are aborted
  • Preventing race conditions in async code

Usage

Basic Example

import { abortable } from 'p-abort';

const operation = abortable($ => async (id: string) => {
  // Step 1: Fetch user data
  const user = await $(fetchUser(id));
  
  // Step 2: Fetch user's posts
  const posts = await $(fetchPosts(user.id));
  
  // Step 3: Process posts
  const processed = await $(processPosts(posts));
  
  return processed;
});

// Start the operation
const promise = operation('user123');

// Later, abort if needed
setTimeout(() => {
  promise.abort();
}, 1000);

// Handle result
const result = await promise;
if (result.ok) {
  console.log('Success:', result.data);
} else {
  console.log('Operation was aborted');
}

With Cleanup

import { abortable } from 'p-abort';

const uploadWithProgress = abortable($ => async (file: File) => {
  const controller = new AbortController();
  
  // Register cleanup function
  $.cleanup(() => {
    controller.abort();
    console.log('Upload cancelled, cleaning up...');
  });
  
  // Start upload
  const response = await $(uploadFile(file, { signal: controller.signal }));
  
  // Process response
  return response;
});

const upload = uploadWithProgress(myFile);

// Cancel upload
upload.abort();

Function Wrapping

The $ utility can also wrap functions to make them abort-aware:

import { abortable } from 'p-abort';

const processData = abortable($ => async (items: string[]) => {
  // Wrap an existing function to be abort-aware
  const abortableFetch = $(fetchData);
  
  const results = [];
  for (const item of items) {
    const data = await abortableFetch(item);
    results.push(data);
  }
  
  return results;
});

Parallel Operations

Use $.all() to run multiple operations in parallel while maintaining abort capability:

const parallelFetch = abortable($ => async (ids: string[]) => {
  // Fetch all data in parallel
  const promises = ids.map(id => $(fetchData(id)));
  const results = await $.all(promises);
  
  return results;
});

API

abortable(fn)

Creates an abortable operation from a function that receives an abort-aware utility.

Parameters

  • fn: A function that receives the $ utility and returns an async function

Returns

A function that returns a Promise with an additional abort() method.

Promise Result

The returned promise resolves to:

  • { ok: true, data: T } on successful completion
  • { ok: false } if the operation was aborted

$ Utility

The $ utility provides several methods for making operations abort-aware:

$(promise)

Wraps a promise or value to be abort-aware. If the operation is aborted before completion, it throws an AbortedError.

$(fn)

Wraps a function to make it abort-aware. The wrapped function will check for abortion before and after execution.

$.cleanup(fn)

Registers a cleanup function to be called when the operation completes or is aborted. Cleanup functions are executed in reverse order of registration (LIFO). Useful for resource cleanup.

$.all(array)

Wraps multiple promises in a Promise.all-like operation. All promises become abort-aware and the entire operation can be cancelled.

$.abort()

Manually aborts the current operation from within the operation function.

runAbortable(fn)

Creates and immediately runs an abortable operation without parameters.

Parameters

  • fn: A function that receives the $ utility and returns a value or promise

Returns

An AbortableTask that can be aborted and resolves to a result object.

import { runAbortable } from 'p-abort';

const task = runAbortable(async $ => {
  const data = await $(fetchData());
  return data;
});

// Can abort the task
task.abort();

const result = await task;
if (result.ok) {
  console.log('Result:', result.data);
} else {
  console.log('Task was aborted');
}

Error Handling

When an operation is aborted, any in-progress steps are cancelled and the promise resolves to { ok: false }. Other errors are propagated normally. You don't need to manually handle AbortedError as it's handled internally.

Advanced Usage

Chaining Operations

const complexWorkflow = abortable($ => async (input: string) => {
  // Step 1: Validate
  const validated = await $(validateInput(input));
  
  // Step 2: Transform
  const transformed = await $(transformData(validated));
  
  // Step 3: Save with retry
  const saved = await $(retry(() => saveData(transformed), 3));
  
  // Step 4: Notify
  await $(sendNotification(saved));
  
  return saved;
});

Resource Management

const fileProcessor = abortable($ => async (filePath: string) => {
  const file = await $(openFile(filePath));
  
  // Ensure file is closed on abort
  $.cleanup(() => {
    file.close();
    console.log('File closed due to abort');
  });
  
  const content = await $(readFile(file));
  const processed = await $(processContent(content));
  
  return processed;
});

TypeScript Support

This package is written in TypeScript and provides full type safety:

interface UserData {
  id: string;
  name: string;
}

const getUser = abortable($ => async (id: string): Promise<UserData> => {
  const response = await $(fetch(`/api/users/${id}`));
  return response.json();
});

// Type is inferred as:
// const getUser: (id: string) => Promise<
//   { ok: true; data: UserData } | { ok: false }
// > & { abort: () => void }

License

MIT © RanolP