Skip to content

Frelseren/promise-task-maps

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Promise Task Maps

Promise-based task mapping operators inspired by RxJS: switchMap, concatMap, mergeMap, and exhaustMap.

This package is framework-agnostic and works in browser environments, including LWC.

Why this library

RxJS operators are excellent for stream pipelines, but many codebases only need Promise-based task control:

  • switchMap: keep only the latest task result
  • concatMap: queue and execute tasks one-by-one
  • mergeMap: run tasks concurrently with an optional limit
  • exhaustMap: ignore new tasks while one is in progress

Install

npm install @frelsren/promise-task-maps

API

type PromiseTask<I, O> = (input: I, context: { signal: AbortSignal; callId: number }) => Promise<O> | O;

type TaskRunner<I, O> = {
  execute(input: I): Promise<O | undefined>;
  cancel(reason?: string): void;
};

Usage

import { createSwitchMap } from "@frelsren/promise-task-maps";

const searchUsers = createSwitchMap(async (query: string, { signal }) => {
  const response = await fetch(`/api/users?q=${encodeURIComponent(query)}`, { signal });
  return response.json();
});

// Typing fast in a search box calls execute repeatedly.
// Older in-flight calls are canceled/ignored; only the latest resolves with data.
const result = await searchUsers.execute("nic");

concatMap example

import { createConcatMap } from "@frelsren/promise-task-maps";

const saveDraft = createConcatMap(async (payload: { id: string; body: string }, { signal }) => {
  const response = await fetch(`/api/drafts/${payload.id}`, {
    method: "PUT",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ body: payload.body }),
    signal
  });
  return response.ok;
});

// Calls are queued and executed in order to avoid race conditions.
await Promise.all([
  saveDraft.execute({ id: "a1", body: "v1" }),
  saveDraft.execute({ id: "a1", body: "v2" }),
  saveDraft.execute({ id: "a1", body: "v3" })
]);

mergeMap example

import { createMergeMap } from "@frelsren/promise-task-maps";

const fetchProfile = createMergeMap(
  async (userId: string, { signal }) => {
    const response = await fetch(`/api/users/${userId}`, { signal });
    return response.json();
  },
  { concurrency: 3 }
);

// Up to 3 requests run in parallel; remaining calls wait in queue.
const profiles = await Promise.all([
  fetchProfile.execute("u1"),
  fetchProfile.execute("u2"),
  fetchProfile.execute("u3"),
  fetchProfile.execute("u4")
]);

exhaustMap example

import { createExhaustMap } from "@frelsren/promise-task-maps";

const submitOrder = createExhaustMap(async (order: { items: string[] }, { signal }) => {
  const response = await fetch("/api/orders", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(order),
    signal
  });
  return response.json();
});

// Double-click protection: second call returns undefined while first is in flight.
const firstAttempt = submitOrder.execute({ items: ["sku-1"] });
const secondAttempt = submitOrder.execute({ items: ["sku-1"] });

await firstAttempt;  // order accepted
await secondAttempt; // undefined

LWC example

import { LightningElement } from "lwc";
import { createSwitchMap } from "@frelsren/promise-task-maps";

export default class UserLookup extends LightningElement {
  users = [];

  lookup = createSwitchMap(async (query: string, { signal }) => {
    const res = await fetch(`/services/apexrest/users?q=${encodeURIComponent(query)}`, { signal });
    return res.json();
  });

  async handleInput(event: Event) {
    const target = event.target as HTMLInputElement;
    const data = await this.lookup.execute(target.value);
    if (data) {
      this.users = data;
    }
  }

  disconnectedCallback() {
    this.lookup.cancel("component disconnected");
  }
}

Development

npm install
npm test
npm run build

About

RxJS-like mapping operators for Promise-based task management

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors