mitt、tiny-emitter 发布订阅源码解析
了解一个包从简介和使用开始,于是老套路,先去 npmjs 看看这个包的 api
javascript
import mitt from 'mitt'
const emitter = mitt()
// listen to an event
emitter.on('foo', (e) => console.log('foo', e))
// listen to all events
emitter.on('*', (type, e) => console.log(type, e))
// fire an event
emitter.emit('foo', { a: 'b' })
// clearing all events
emitter.all.clear()
// working with handler references:
function onFoo() {}
emitter.on('foo', onFoo) // listen
emitter.off('foo', onFoo) // unlisten
简单看下来就是先用 on 定义一个事件方法,然后通过 emit 进行触发执行这个事件方法。
javascript
var Emitter = require('tiny-emitter')
var emitter = new Emitter()
emitter.on('some-event', function (arg1, arg2, arg3) {
//
})
emitter.emit('some-event', 'arg1 value', 'arg2 value', 'arg3 value')
初步看,两个库的使用方式差不多,毕竟都是发布订阅,上源码
mitt
typescript
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) {
const handlers: Array<GenericEventHandler> | undefined = all!.get(type)
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, or `'*'`
* @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) {
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!)
})
}
},
}
}
tiny-emitter
javascript
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
未完待续。。。。