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

async-event-channel

v2.3.1

Published

Two-way communication asynchronous event channel

Downloads

6

Readme

async-event-channel

English | 简体中文

双向通信异步事件通道

安装

npm install async-event-channel

快速理解

// 事件通信实例
const dom = document.querySelector('.ctx');

// 注册事件
dom.addEventListener('click', function(event) {
  console.log('收到的事件');
});
// 再次注册事件
dom.addEventListener('click', function(event) {
  console.log('再次收到事件');
});

// 触发事件
dom.dispatchEvent(new Event('click'));
// 再次触发事件
dom.dispatchEvent(new Event('click'));

对比

import AsyncEventChannel from 'async-event-channel';
// 或
// const { default: AsyncEventChannel } = require('async-event-channel');
// 或
// import AsyncEventChannel from 'async-event-channel/es5';

// 事件通信实例
const channel = new AsyncEventChannel();

// 注册事件
channel.on('click', function(...args) {
  console.log('收到的事件', args);
});
// 再次注册事件
channel.on('click', function(...args) {
  console.log('再次收到事件', args);
});

// 触发事件
channel.emit('click', '事件数据1', '事件数据2');
// 再次触发事件
channel.emit('click', '事件数据3', '事件数据4');

异步通信

import AsyncEventChannel from 'async-event-channel';

const channel = new AsyncEventChannel();

// 首先发出事件 (仅当事件未注册时,才会异步等待发送事件)
channel.emit('timeout', '异步事件');

// 稍后注册事件
setTimeout(() => {
  channel.on('timeout', function(data) {
    console.log(data); // 异步事件
  });
}, 1000);

获取事件返回值(双向通信)

channel.on('get', function(data) {
  console.log(data); // 事件数据
  return '返回值';
});

const result = channel.emit('get', '事件数据');
console.log(result.values[0]); // 返回值

异步获取事件返回值(双向通信)

channel.asyncEmit('get', '事件数据').promise.then(result => {
  console.log(result.values[0]); // 返回值
});

setTimeout(() => {
  channel.on('get', function(data) {
    console.log(data); // 事件数据
    return '返回值';
  });
}, 1000);

同步获取事件返回值(双向通信)

channel.on('get', function(data) {
  console.log(data); // 事件数据
  return '返回值';
});

// 如果未注册事件,将获得 undefined
const values = channel.immedEmit('get', '事件数据');
console.log(values[0]); // 返回值

取消侦听事件

const { cancel } = channel.on('cancel', function() {
  return '取消事件';
});

// 取消侦听事件
cancel();

const values = channel.immedEmit('cancel');
console.log(values); // []

取消等待中的触发事件

const { cancel } = channel.emit('cancel', '取消事件');

// 取消等待中的触发事件
cancel();

// 无法接收事件
channel.on('cancel', function(data) {
  console.log(data);
});

取消指定通道上的监听事件和触发事件

channel.on('cancel', function() {
  return '取消事件';
});
channel.on('cancel', function() {
  return '再次取消事件';
});

channel.off('cancel');

const values = channel.immedEmit('cancel');
console.log(values); // []

监听过程

// 监听过程,从注册事件到触发事件和取消事件,只监听事件,不触发事件
channel.watch('watch', function(data) {
  // 注意:无法保证监听过程的执行顺序
  console.log(data); // { "id": 1, "event": "on", "progress": "register", "type": "watch", "value": function() {...} }
  if (data.id === id) {
    console.log('匹配成功');
  }
});

const { id } = channel.on('watch', function() {
  return '监听过程';
});

查询是否还存在

const { id } = channel.on('exists', function() {});

console.log(channel.hasId(id)); // true
console.log(channel.hasType('exists')); // true

导入导出

const channel_old = new AsyncEventChannel();
const channel_new = new AsyncEventChannel();

channel_old.on('import', function() {
  return '导入事件';
});

// 导出事件通道数据
const data = channel_old.export();

// 导入事件通道数据
channel_new.import(...data);

// 导入事件通道数据后,可以使用导入的事件通道数据
const values_new = channel_new.immedEmit('import');
console.log(values_new[0]); // 导入事件

// 相当于复制,不会影响原事件通道数据
const values_old = channel_old.immedEmit('import');
console.log(values_old[0]); // 导入事件

监听事件和微任务

let current = 0;

channel.on('microtask', function() {
  // 和Promise.resolve().then()一样,回调函数在当前事件循环的微任务队列中执行
  console.log('执行时刻', current); // 1
});

// 立刻触发事件
channel.emit('microtask');

current = 1;

只监听一次事件(双向通信)

channel.once('once', function() {
  return '一次事件';
});

const values = channel.immedEmit('once');
console.log(values[0]); // 一次事件

const valuesAgain = channel.immedEmit('once');
console.log(valuesAgain); // []

立即监听事件一次(双向通信)

// 永远不会触发事件
channel.immedOnce('immedOnce', function() {
  console.log('之前');
});

channel.emit('immedOnce');

channel.immedOnce('immedOnce', function() {
  console.log('之后'); // 之后
});

取消事件的统一收集

import AsyncEventChannel, { asyncEventChannelScope } from 'async-event-channel';

const channel = new AsyncEventChannel();
const { ctx, cancel } = asyncEventChannelScope(channel);

ctx.on('cancel', function() {
  return '取消事件';
});
channel.once('cancel', function() {
  return '再次取消事件';
});

// 取消所有事件
cancel();

const values = ctx.immedEmit('cancel');
console.log(values); // []

// 仅取消代理实例上的事件
const valuesAgain = channel.immedEmit('cancel');
console.log(valuesAgain); // ["再次取消事件"]

配置事件类型名单进行作用域隔离

import AsyncEventChannel, { asyncEventChannelScope } from 'async-event-channel';

const channel = new AsyncEventChannel();
const { ctx } = asyncEventChannelScope(channel, {
  include: [
    {
      type: 'only',
      handlers: ['emit']
    }
  ]
});

ctx.emit('only', '仅支持触发事件');

// 注册或取消事件会报错
// ctx.on('only', function() {});
// ctx.off('only');

// 只能在原事件通道上注册事件
channel.on('only', function(res) {
  console.log(res); // 仅支持触发事件
});

// 名单外的事件类型不受影响
ctx.on('other', function() {
  return '其他事件';
});

const values = ctx.immedEmit('other');
console.log(values[0]); // 其他事件

生成固定的事件类型

import AsyncEventChannel, { useCreateEventChannel } from 'async-event-channel';

const channel = new AsyncEventChannel();
const createEventChannel = useCreateEventChannel(channel);

const fixed = createEventChannel();

fixed.on(function() {
  return '固定事件';
});

const values = fixed.immedEmit();
console.log(values[0]); // 固定事件

设置禁用异步触发事件

const channel = new AsyncEventChannel({ isEmitCache: false });

channel.emit('disable', '禁用事件');

// 无法接收事件
setTimeout(() => {
  channel.on('disable', function(data) {
    console.log(data);
  });
}, 1000);

设置同一通道只能注册一个事件

const channel = new AsyncEventChannel({ isOnOnce: true });

channel.on('once', function() {
  return '一次事件';
});

// 覆盖上一个事件
channel.on('once', function() {
  return '第二次一次事件';
});

const values = channel.immedEmit('once');
console.log(values[0]); // 第二次一次事件

设置同一通道只能触发一个事件

const channel = new AsyncEventChannel({ isEmitOnce: true });

channel.emit('once', '一次事件');

// 覆盖上一个等待事件
channel.emit('once', '第二次一次事件');

// 只能接收最后一个事件
channel.on('once', function(data) {
  console.log(data); // 第二次一次事件
});

仅设置指定的事件类型

const options = new Map();
options.set('only', { isEmitCache: false });
const channel = new AsyncEventChannel(null, options);

channel.emit('only', '指定事件');

// 无法接收事件
setTimeout(() => {
  channel.on('only', function(data) {
    console.log(data);
  });
}, 1000);

channel.emit('other', '其他事件');

// 可以接收事件
setTimeout(() => {
  channel.on('other', function(data) {
    console.log(data); // 其他事件
  });
}, 1000);

修改全局默认配置

import AsyncEventChannel from 'async-event-channel';

AsyncEventChannel.defaultOptions.isEmitCache = false;

配置项的优先级

// 指定
new AsyncEventChannel(null, new Map([ ['only', { isEmitCache: true }] ]))

// 当前
new AsyncEventChannel({ isEmitCache: true })

// 全局
AsyncEventChannel.defaultOptions.isEmitCache

// 指定 > 当前 > 全局

可用作事件类型的值

可以使用任何类型的值,包括字符串,数字,对象,数组,符号,null等

const channel = new AsyncEventChannel();

channel.on('string', function() {});
channel.on(1, function() {});
channel.on({}, function() {});
channel.on([], function() {});
channel.on(Symbol('symbol'), function() {});
channel.on(null, function() {});
channel.on(function() {}, function() {});

异步任务队列

与事件通道无关

import { AsyncTaskQueue } from 'async-event-channel';

// 事件类型可以是任何类型的值
const types = ['a', 1, null, ''];
// 就绪后是否自动执行
const oneAuto = false;

// 创建异步任务队列
const queue = new AsyncTaskQueue(types, oneAuto);

// 将任务添加到队列
queue.on('a', function(state) {
  console.log(1)
  return 'a';
});
queue.on(null, async function(state) {
  console.log(3)
  await new Promise(resolve => setTimeout(resolve, 1000));
  return null;
});
setTimeout(() => {
  queue.on(1, function(state) {
    console.log(2)
    queue.cancel(); // 取消本次任务队列的执行
    return 1;
  });
}, 1000);
queue.on('', function(state) {
  console.log(4)
  return '';
});

// 准备就绪
queue.onLoad(function() {
  console.log('准备就绪');
  queue.start(0).then(result => {
    // 本次任务队列执行结果
    console.log(result);
  }).catch(error => {
    // 本次任务队列执行错误
    console.error(error);
  });
});

// 任务队列是否正在运行
console.log(queue.isRunning)