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

async-message

v0.3.0

Published

Call another threads as simple as a function call

Downloads

3

Readme

async-message

使用一个统一的API调用其他窗口/线程的方法,像调用一个异步函数一样简单

npm version npm bundle size (minified)

# use npm
npm install --save async-message
# use yarn
yarn add async-message
# use pnpm
pnpm install async-message

特性

  • 多平台支持,web / node / electron
  • 接口适配,自定义不同场景
  • 完美支持Typescript
  • 自定义序列化/反序列化插件

快速开始

例子

// master.ts
import { caller } from 'async-message';
import { WorkerChannel } from 'async-message/web';
import type { Counter } from './workers/counter';

const worker = new Worker('./workers/counter');
const channel = new WorkerChannel(worker);
const counter = caller<Counter>(channel);

const count = await counter.getCount();
console.log('current cout:', count);

const nextCount = await counter.increment();
console.log('next count:', nextCount);
// workers/counter.ts
import { producer } from 'async-message';
import { WorkerChannel } from 'async-message/web';

const channel = new WorkerChannel();

const counter = {
  count: 0,
  getCount() {
    return this.count;
  },
  increment() {
    return ++this.count;
  },
  decrement() {
    return --this.count;
  },
}

producer(channel, counter);

export type Counter = typeof counter;

在web worker例子中,主线程调用工作线程导出的counter

  • caller通过channel发送消息给worker
  • worker里通过channel接受到caller的消息,并执行counter的方法
  • 方法执行结果再通过channel发送给caller,完成一次调用

channel

负责发送消息 / 接受消息 / 广播消息channel继承emitter

caller(channel, timeout)

负责通过channel代理对worker中producer目标的调用,所有方法均返回一个promise

producer(channel, target)

负责通过channel导出target给其他caller调用

平台

Web

import { WorkerChannel, WindowChannel } from 'async-message/web';

// for worker 主线程
new WorkerChannel(new Worker('./worker.js'));
// for worker 工作线程
new WorkerChannel();

// for shared worker 主线程
new WorkerChannel(new SharedWorker('./worker.js'));
// for shared worker 工作线程
new WorkerChannel();

// for iframe 父窗口
const iframe = document.querySelector('iframe');
new WindowChannel(iframe.contentWindow, 'https://xxx.xx');
// for iframe 子窗口
new WindowChannel('https://xxx.xx');

// for window 父窗口
const win = window.open('https://xxx.xx');
new WindowChannel(win, 'https://xxx.xx');
// for window 子窗口
new WindowChannel('https://xxx.xx');

Node

import { WorkerChannel } from 'async-message/node';
import { Worker } from 'worker_threads';

// for worker 主线程
new WorkerChannel(new Worker('./worker.js'));
// for worker 工作线程
new WorkerChannel();

Electron

import { IpcChannel } from 'async-message/electron';

// for main 主线程
new IpcChannel();
// for renderer 渲染线程
new IpcChannel();

序列化

回调函数

数据传递的时候函数无法被序列化,需要一些额外的手段来传递回调函数,通过callbackSerializer赋予channel序列化/反序列化函数的能力

需要在传递函数的时候注册用registerCallback包裹,注销的时候用unregisterCallback包裹,否则此函数会常驻于内存

// master.ts
import { caller } from 'async-message';
import { WorkerChannel } from 'async-message/web';
import { callbackSerializer, registerCallback, unregisterCallback } from 'async-message/serializer'
import type { Target } from './workers/target';

const worker = new Worker('./workers/target');

const channel = new WorkerChannel(worker);
channel.registerSerializer(callbackSerializer); // 这一步是必须的

const target = caller<Target>(channel);

const callback = () => {};

await target.addEventListener('test', registerCallback(callback));

await target.removeEventListener('test', unregisterCallback(callback));
// workers/target.ts
import { producer } from 'async-message';
import { WorkerChannel } from 'async-message/web';
import { callbackSerializer } from 'async-message/serializer'

const channel = new WorkerChannel();
channel.registerSerializer(callbackSerializer); // 这一步是必须的

const target = {
  addEventListener(type: string, listener: (...args: any[]) => void) {
    // do something
  },
  removeEventListener(type: string, listener: (...args: any[]) => void) {
    // do something
  }
}

producer(channel, target);

export type Target = typeof counter;

callbackSerializer会遍历所有数据字段,如果传递的数据量太大,请自定义serializer

高级用法

自定义channel

import { Channel, Message } from 'async-message';

class MyChannel extends Channel {
  postMessage(message: Message) {
    // do something
  }
}

自定义serializer

import { Serializer, Channel } from 'async-message'

const mySerializer: Serializer = {
  onRegister(channel: Channel) {
    // do something
  },
  onUnregister(channel: Channel) {
    // do something
  },
  serialize(value: unknown, fallback: (value: unknown) => any, poster: Poster) {
    // do something
  },
  deserialize(value: unknown, fallback: (value: unknown) => any, poster: Poster) {
    // do something
  }
}