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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@webfill/async-context

v1.0.0

Published

🗺️ An experimental AsyncContext polyfill

Downloads

39

Readme

AsyncContext polyfill for Node.js and the browser

🗺️ An experimental AsyncContext polyfill

⚠️ Experimental API
🎣 Uses Node.js' AsyncLocalStorage if possible
🧅 Works with Bun via Zone.js
🦕 Works with Deno via their Node.js compat layer
🌐 Works in the browser via Zone.js!

Installation

npm Yarn pnpm jsDelivr

This package can be installed locally using npm, Yarn, pnpm, or your other favorite package manager of choice:

npm install @webfill/async-context

If you're using Deno, you can install this package using the new npm: specifiers, or directly from a Deno-compatible npm CDN like esm.sh:

import {} from "npm:@webfill/async-context";
import {} from "https://esm.sh/@webfill/async-context";

If you want to use this package in the browser without needing a build tool to bundle your npm dependencies, you can use an npm CDN like esm.sh or jsDelivr to import it directly from a URL:

import {} from "https://esm.sh/@webfill/async-context";
import {} from "https://esm.run/@webfill/async-context";

Usage

Node.js Deno Browser Bun

This package exports the AsyncContext namespace. To get started, you can create a new AsyncContext.Variable and use it in various places. When you use the .run(value, f) method, it will cascade that value throughout the entire (possibly asynchronous) execution of any subsequent functions. Here's a quick demo:

import AsyncContext from "@webfill/async-context";

const message = new AsyncContext.Variable({ defaultValue: "Hello" });

message.run("Hi", async () => {
  await fetch("https://jsonplaceholder.typicode.com/todos/1");
  console.log(message.get());
  //=> "Hi"
});

message.run("Hey", () => {
  setTimeout(() => {
    console.log(message.get());
    //=> "Hey"
  }, 10);
});

console.log(message.get());
//=> "Hello"

For a more practical example, you could use an AsyncContext.Variable to track a Request's ID across many different asynchronous functions without resorting to "argument drilling":

const id = new AsyncContext.Variable();
let i = 0;
globalThis.addEventListener("fetch", (event) => {
  id.run(++i, () => {
    event.respondWith(handleRequest(event.request));
  });
});

function logError(message) {
  // Note that this is two calls deep in an async chain! Yet we still get the
  // correct ID that was set via 'id.run()'
  console.error(id.get(), message);
  //=> '1' 'Not found'
  //=> '2' 'Not found'
}

async function handleRequest(request) {
  if (request.url === "/") {
    await doThing();
    return new Response(`Hello, ${id.get()} 👋`);
    //=> 'Hello, 1 👋'
    //=> 'Hello, 2 👋'
  } else {
    await doThing();
    logError("Not found");
    return new Response(`${id.get()} not found.`, { status: 404 });
    //=> '1 not found.'
    //=> '2 not found.'
  }
}

Here's the example from the proposal for reference.

const asyncVar = new AsyncContext.Variable();

// Sets the current value to 'top', and executes the `main` function.
asyncVar.run("top", main);

function main() {
  // AsyncContext.Variable is maintained through other platform queueing.
  setTimeout(() => {
    console.log(asyncVar.get()); // => 'top'

    asyncVar.run("A", () => {
      console.log(asyncVar.get()); // => 'A'

      setTimeout(() => {
        console.log(asyncVar.get()); // => 'A'
      }, randomTimeout());
    });
  }, randomTimeout());

  // AsyncContext.Variable runs can be nested.
  asyncVar.run("B", () => {
    console.log(asyncVar.get()); // => 'B'

    setTimeout(() => {
      console.log(asyncVar.get()); // => 'B'
    }, randomTimeout());
  });

  // AsyncContext.Variable was restored after the previous run.
  console.log(asyncVar.get()); // => 'top'

  // Captures the state of all AsyncContext.Variable's at this moment.
  const snapshotDuringTop = new AsyncContext.Snapshot();

  asyncVar.run("C", () => {
    console.log(asyncVar.get()); // => 'C'

    // The snapshotDuringTop will restore all AsyncContext.Variable to their snapshot
    // state and invoke the wrapped function. We pass a function which it will
    // invoke.
    snapshotDuringTop.run(() => {
      // Despite being lexically nested inside 'C', the snapshot restored us to
      // to the 'top' state.
      console.log(asyncVar.get()); // => 'top'
    });
  });
}

function randomTimeout() {
  return Math.random() * 1000;
}

Proposed Solution | Async Context for JavaScript