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

plugge

v1.3.2

Published

基于上下文的高性能高可靠轻量的插件化库

Downloads

18

Readme

pluggle

基于上下文的高性能高可靠轻量化插件化库

特点

  1. 任务分片 当在浏览器环境多个任务(异步注册时)执行超过12ms(预留4ms 左右 render)时会自动进行任务分片到不同的事件周期(或帧),不阻塞UI响应.
  2. 隔离: 保证异常影响范围最小, A插件的错误不影响B插件, 插件间的通信与Host通信隔离.
  3. 灵活: 支持多种方法注册动作:
    • 已触发注册:onAlready/onAlreadySync: 用于像ready等只触发一次的事件;
    • 异步并行: emitAsyncParalle: 用于并行执行插件Hook,性能更好;
    • 异步串行:emitAsyncSeries: 用于串行执行插件Hook, 用于插件间有数据或流程上的依赖;
    • 单次:once/onceSync: 触发后解绑;
    • 同/异步:on/onSync: 同步执行时该时该的插件可以马上获取数据变更, 异步时,有分片性能更好;
    • 所有/任一: onEveryOnce/onAnyOnce: 监听事件列表的所有/任一事件触发时触发回调
    • 支持事件的优先级和分包加载;
    • 支持实现有序广播和拦截广播: 拦截广播主要用于事件Hook没有处理时, 有兜底的行为。比如关机事件, 当没有软件处理关机事件, 需要正常关机;
  4. 中心式的事件分发: 避免网状的信息流,过长的调用链引起的事件泥潭和缺陷定位复杂.
  5. 可靠: 有效代码函数测试覆盖率100%, 行覆盖率98%+.
  6. 轻量: 2kb gzipped.

Usage

tnpm i plugge --save
    import Pluggable from 'plugge'
    class Reader extends Pluggable{
      constructor(){
        super()
      }

      init(){
        this.emitAsyncSeries('init')
      }

      nextPage(){
        this.emit('nextPage')
      }
    }
    //注册默认或高优先级插件, 在实例前时注入
    Reader.registerDefaultPlugin(function(){
      this.on('init', function(){
        this.context = {pageIndex: 1, imgIndex: 1}
      })

      this.emit('inited')
    })

   //实例化后延迟注入, 用于一些低优先级或插件分包加载
    const reader = new Reader()
    reader.registerPlugin(function(){
      this.onSync('nextPage', function(){
        this.context.pageIndex += 1
      })
    })

通信

插件间的通信

await host.eventBus.emitAsyncParalle('pluginName.moduleName:eventName', params)
host.eventBus.emit('pluginA.play:click', params)
host.eventBus.emit('pluginB.space:press', params)

// 多事件注册, 逗号分开
host.eventBus.onSync('pluginA.play:click,pluginB.space:press,pluginName.moduleName:eventName', async params =>{/*do something*/})
// 接收器的优先级
host.eventBus.once('pluginA.play:click', async params =>{/*do something*/}, {priority: 1001})

插件与Host通信

插件与Host通信直接在Host上广播事件或是用插件间的通信方法同步信息

// 同样支持 多事件注册, 接收器的优先级的api
host.emit('Host:ready', params)
host.onAlready('Host:ready', params =>{/*do something*/}) 

拦截广播和有序广播

pluggable内未实现广播的拦截, 但可以结合 priority, context很容易实现有序广播的插件.

插件结构流程图

测试覆盖率

除了Typscript 生成的函数外, 函数覆盖率100%, 行覆盖率99%以上

=============================== Coverage summary ===============================
Statements   : 93.22% ( 275/295 )
Branches     : 78.72% ( 111/141 )
Functions    : 96.3% ( 78/81 )
Lines        : 98.31% ( 233/237 )
================================================================================

测试用例

npm t

Built With

  • 腾讯视频漫画阅读器
  • Glama(腾讯视频内部框架)

兼容性

支持所有浏览器和node版本, 但Chrome 45, Safari 8, Node 4 以下注意polyfill以下api.

Array.prototype.findIndex
generator (for async)

API

说明:
on, once, onAlready均为非阻塞注册事件, 但下个动作无法立即获取事件回调中的改动。
同步阻塞版本为:onSync, onceSync, onAlreadySync。 同步事件的优先级永远大于异步。

详情使用请查看源码test文件测试用例.

export declare class ListenerDetail {
    /**
     * 建议小于 10000, 大于10000内部使用
     *
     * @type {number}
     * @memberof ListenerDetail
     */
    priority?: number;
    constructor(priority?: number);
}
export declare enum PluggableInnerEvent {
    PluggableReady = "PluggableReady",
    PluggableHookError = "PluggableHookError"
}
export default class Pluggable<Context> {
    static disableChunk: boolean;
    static defaultPlugins: Array<Function>;
    isNodeEnv: boolean;
    /**
     * 插件间的事件通信, 用于不适合放在Host的中的事件
     */
    eventBus: Pluggable<any>;
    context: Context;
    /**
     * 注册默认的插件,在实例化前调用
     */
    static registerDefaultPlugin(plugins: any): void;
    /**
     *Creates an instance of Pluggable.
     * @param {boolean} [isPure=false] 纯净的实例不会生成eventBus, 不会注册默认插件,只提供基础的发布订阅能力
     * @memberof Pluggable
     */
    constructor(isPure?: boolean);
    /**
     *注册插件
     */
    registerPlugin(plugin: Function | {
        install: (...args: any[]) => any;
    }, context?: any): any;
    /**
     * alias of registerPlugin
     *
     * @memberof Pluggable
     */
    use(...args: any[]): void;
    /**
     * 注册事件
     * @param {string} events 支持多事件, 用逗号隔开, 比如on('eventA,eventB', f)
     * @param {Function} callback
     * @memberof Pluggable
     */
    on(events: string, callback: Function, detail?: ListenerDetail): void;
    onSync(events: string, callback: Function, detail?: ListenerDetail): void;
    off(events: string, callback: Function): void;
    onAllEvent(callbak: Function): void;
    emit(event: string, ...args: any[]): Array<any>;
    /**
     *异步并行执行事件, onSync生效
     *
     * @param {*} event
     * @returns
     * @memberof Pluggable
     */
    emitAsyncParalle(event: string, ...args: any[]): Promise<any[]>;
    /**
     * 异步串行执行事件, , onSync生效
     *
     * @param {*} event
     * @memberof Pluggable
     */
    emitAsyncSeries(event: string, ...args: any[]): Promise<any>;
    once(event: string, callback: Function, detail?: ListenerDetail): void;
    onceSync(event: string, callback: Function, detail?: ListenerDetail): void;
    /**
     * 当events列表中所有事件发生时触发回调, 只触发一次
     *
     * @param {string[]} events
     * @param {Function} callback
     * @param {ListenerDetail} [detail]
     * @memberof Pluggable
     */
    onEveryOnce(events: string[], callback: Function, detail?: ListenerDetail): void;
    /**
     * 当events列表中任意事件发生时触发回调, 只触发一次
     *
     * @param {string[]} events
     * @param {Function} callback
     * @param {ListenerDetail} [detail]
     * @memberof Pluggable
     */
    onAnyOnce(events: string[], callback: Function, detail?: ListenerDetail): void;
    /**
     * 注册可能已触发的事件, 用于Ready, beforeReady等只触发一次的事件Hook
     *
     * @param {string} event
     * @param {*} callback
     * @memberof Pluggable
     */
    onAlready(event: string, callback: Function, detail?: ListenerDetail): void;
    onAlreadySync(event: string, callback: Function, detail?: ListenerDetail): void;
    destroy(): void;
}