1、mitt
export type EventType = string | symbol;
// An event handler can take an optional event argument
// and should not return a value
export type Handler<T = unknown> = (event: T) => void;
export type WildcardHandler<T = Record<string, unknown>> = (
type: keyof T,
event: T[keyof T]
) => void;
// An array of all currently registered event handlers for a type
export type EventHandlerList<T = unknown> = Array<Handler<T>>;
// 通配符事件处理程序列表
export type WildCardEventHandlerList<T = Record<string, unknown>> = Array<WildcardHandler<T>>;
// A map of event types and their corresponding event handlers.
export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map<
keyof Events | '*',
EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>
>;
export interface Emitter<Events extends Record<EventType, unknown>> {
all: EventHandlerMap<Events>; //事件处理函数数组
//注册某事件,并监听
on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void;
on(type: '*', handler: WildcardHandler<Events>): void;
//关闭某事件监听
off<Key extends keyof Events>(type: Key, handler?: Handler<Events[Key]>): void;
off(type: '*', handler: WildcardHandler<Events>): void;
//触发某事件
emit<Key extends keyof Events>(type: Key, event: Events[Key]): void;
emit<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never): void;
}
/**
* Mitt: Tiny (~200b) functional event emitter / pubsub.
* @name mitt
* @returns {Mitt}
*/
export default function mitt<Events extends Record<EventType, unknown>>(
all?: EventHandlerMap<Events>
): Emitter<Events> {
type GenericEventHandler =
| Handler<Events[keyof Events]>
| WildcardHandler<Events>;
all = all || new Map();
return {
/**
* A Map of event names to registered handler functions.
* //所有注册函数
*/
all,
/**
* Register an event handler for the given type.
* @param {string|symbol} type Type of event to listen for, or `'*'` for all events
* @param {Function} handler Function to call in response to given event
* @memberOf mitt
*/
on<Key extends keyof Events>(type: Key, handler: GenericEventHandler) {
// 获取 type 对应的的 事件处理函数数组
const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
// 存在,说明设置过,handlers 已经是数组,直接 push 进去
if (handlers) {
handlers.push(handler);
}
else {
//不存在,注册事件并监听
all!.set(type, [handler] as EventHandlerList<Events[keyof Events]>);
}
},
/**
* Remove an event handler for the given type.
* If `handler` is omitted, all handlers of the given type are removed.
* @param {string|symbol} type Type of event to unregister `handler` from (`'*'` to remove a wildcard handler)
* @param {Function} [handler] Handler function to remove
* @memberOf mitt
*/
off<Key extends keyof Events>(type: Key, handler?: GenericEventHandler) {
const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
if (handlers) {
if (handler) {
//删除指定的 handler处理函数
handlers.splice(handlers.indexOf(handler) >>> 0, 1);
}
else {
//删除全部
all!.set(type, []);
}
}
},
/**
* Invoke all handlers for the given type.
* If present, `'*'` handlers are invoked after type-matched handlers.
*
* Note: Manually firing '*' handlers is not supported.
*
* @param {string|symbol} type The event type to invoke
* @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
* @memberOf mitt
*/
emit<Key extends keyof Events>(type: Key, evt?: Events[Key]) {
//触发当个事件
let handlers = all!.get(type);
if (handlers) {
(handlers as EventHandlerList<Events[keyof Events]>)
.slice()
.map((handler) => {
handler(evt!);
});
}
//触发所有事件
handlers = all!.get('*');
if (handlers) {
(handlers as WildCardEventHandlerList<Events>)
.slice()
.map((handler) => {
handler(type, evt!);
});
}
}
};
}
1、调试
const emitter = mitt()
// listen to an event
emitter.on('foo', e => console.log('foo', e))
emitter.on('foo', e => console.log('foo1', e))
// listen to all events
emitter.on('', (type, e) => console.log('' + type, e))
emitter.emit('foo', { a:'b' })
emitter.all.clear() //清除所有事件
emitter.on('foo', onFoo)
emitter.off('foo', onFoo) // unlisten
2、缺点
- mitt 支持传入 all 参数,如果 all = {} 而不是 new Map() 那么会报错,不能正常使用,在ts中当然会提醒你
- emit(type, [evt])中只能接受一个参数,要是传多个参数需要将多个参数合并成对象传入,然后在事件处理函数中解构
2、tiny-emitter
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.TinyEmitter = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
function E () {
// Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
}
E.prototype = {
on: function (name, callback, ctx) {
var e = this.e || (this.e = {});
(e[name] || (e[name] = [])).push({
fn: callback,
ctx: ctx
});
return this;
},
once: function (name, callback, ctx) {
var self = this;
function listener () {
self.off(name, listener);
callback.apply(ctx, arguments);
};
listener._ = callback
return this.on(name, listener, ctx);
},
emit: function (name) {
var data = [].slice.call(arguments, 1);
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
var i = 0;
var len = evtArr.length;
for (i; i < len; i++) {
evtArr[i].fn.apply(evtArr[i].ctx, data);
}
return this;
},
off: function (name, callback) {
var e = this.e || (this.e = {});
var evts = e[name];
var liveEvents = [];
if (evts && callback) {
for (var i = 0, len = evts.length; i < len; i++) {
if (evts[i].fn !== callback && evts[i].fn._ !== callback)
liveEvents.push(evts[i]);
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
(liveEvents.length)
? e[name] = liveEvents
: delete e[name];
return this;
}
};
module.exports = E;
module.exports.TinyEmitter = E;
},{}]},{},[1])(1)
});
1、调试
consttiny = newE()
// listen to an event
tiny.on('foo', e=>console.log('foo', e))
tiny.on('foo', e=>console.log('foo1', e))
tiny.emit('foo', { a: 'b' })
tiny.once('haha', (type, e) =>console.log('*' + type, e))
tiny.emit('haha', { a:'b' })
tiny.emit('haha', { a:'b' })
触发一次时,循环时会调用fn函数,即listener,关闭监听,并callbak调用argument,返回结果。
functiononFoo() {}
tiny.on('foo', onFoo) // listen
tiny.off('foo', onFoo) // unliste
3、感谢
tinymitter的once方法真的觉得很高级,真的觉得作者处理这一段的时候很厉害,学到了学到了 感谢老师