golang事件发射与处理插件库emitter的使用

Golang事件发射与处理插件库emitter的使用

emitter包实现了一个基于channel的发布订阅模式。设计目标是使用Golang并发模型而不是简单的回调,并设计一个非常简单的API以便于使用。

为什么选择emitter?

Go拥有强大的并发模型,但在2015年时还没有人将其很好地用于pubsub模式。emitter实现了自己的解决方案,因为它能满足特定的需求。

功能特性

  • 同步/异步事件发射
  • 谓词/中间件
  • 双向通配符
  • 需要时可取消发射
  • 合并来自不同通道的事件
  • 按需浅类型转换
  • 支持传统回调方式

简单示例

e := &emitter.Emitter{}
go func(){
    <-e.Emit("change", 42) // 等待事件成功发送
    <-e.Emit("change", 37)
    e.Off("*") // 取消订阅所有监听器
}()

for event := range e.On("change") {
    // 处理event.Args
    println(event.Int(0)) // 将第一个参数转换为int
}
// 监听器通道已关闭

构造函数

emitter.New 第一个参数是uint类型,表示监听器的缓冲区大小。也可以在运行时通过e.Cap = 10修改缓冲区容量。

默认情况下,emitter为每个监听器使用一个goroutine发送事件。可以通过传递emitter.Sync标志来改变这种行为:e.Use("*", emitter.Sync)。建议在开始时为emitter指定中间件。

通配符

包允许使用通配符进行发布和订阅。这个特性基于path.Match函数。

示例:

go e.Emit("something:special", 42)
event := <-e.Once("*") // 搜索任何事件
println(event.Int(0)) // 会打印42

// 或者用通配符路径发射事件
go e.Emit("*", 37) // 为所有人发射
event := <-e.Once("something:special")
println(event.Int(0)) // 会打印37

中间件

中间件是一个以Event指针为第一个参数的函数。中间件能够:

  1. 修改事件
  2. 需要时跳过事件发射
  3. 修改事件的参数
  4. 指定事件发射的模式

有两种方式添加中间件:

  • 通过.On(“event”, middlewares…)
  • 通过.Use(“event”, middlewares…)

示例:

// 对所有事件使用同步模式
e.Use("*", emitter.Sync)
go e.Emit("something:special", 42)

// 定义谓词
event := <-e.Once("*", func(ev *emitter.Event){
    if ev.Int(0) == 42 {
        // 跳过发送
        ev.Flags = ev.Flags | emitter.FlagVoid
    }
})
panic("永远不会发生")

标志

标志用于描述事件应该如何发射。每个事件(emitter.Event)都有一个.Flags字段,包含作为二进制掩码的标志。

有几种预定义的中间件来设置需要的标志:

  • emitter.Once
  • emitter.Close
  • emitter.Void
  • emitter.Skip
  • emitter.Sync
  • emitter.Reset

可以链式使用这些标志:

e.Use("*", emitter.Void) // 跳过任何事件的发送
go e.Emit("surprise", 65536)
event := <-e.On("*", emitter.Reset, emitter.Sync, emitter.Once) // 为此监听器设置自定义标志
pintln(event.Int(0)) // 打印65536

取消

可以通过关闭done通道来取消任何发射的事件:

done := e.Emit("broadcast", "the", "event", "with", "timeout")

select {
case <-done:
    // 发送完成
case <-time.After(timeout):
    // 超时,取消发射
    close(done)
}

仅回调使用

也可以以更传统的方式使用emitter:

e := &emitter.Emitter{}
e.Use("*", emitter.Void)

go e.Emit("change", "field", "value")
e.On("change", func(event *Event){
    // 在这里处理变化
    field := event.String(0)
    value := event.String(1)
    // ...等等
})

组将不同的监听器合并到一个通道中:

e1 := &emitter.Emitter{}
e2 := &emitter.Emitter{}
e3 := &emitter.Emitter{}

g := &emitter.Group{Cap: 1}
g.Add(e1.On("first"), e2.On("second"), e3.On("third"))

for event := g.On() {
    // 处理事件
    // 事件有OriginalTopic和Topic字段
}

事件

Event是一个包含事件信息的结构体。还有一些辅助方法可以将各种参数转换为boolstringfloat64int等类型:

go e.Emit("*", "some string", 42, 37.0, true)
event := <-e.Once("*")

first := event.String(0)
second := event.Int(1)
third := event.Float(2)
fourth := event.Bool(3)

// 如果不存在则使用默认值
dontExists := event.Int(10, 64)
// 或者类型不匹配时使用默认值
def := event.Int(0, 128)

许可证

MIT


更多关于golang事件发射与处理插件库emitter的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang事件发射与处理插件库emitter的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang事件发射与处理插件库emitter使用指南

emitter是一个轻量级的Go语言事件发射器库,它实现了观察者模式,允许你在应用中实现发布/订阅模式的事件处理机制。下面我将详细介绍emitter的使用方法。

安装

首先安装emitter库:

go get github.com/olebedev/emitter

基本用法

1. 创建事件发射器

package main

import (
	"fmt"
	"github.com/olebedev/emitter"
)

func main() {
	// 创建事件发射器
	emitter := emitter.Emitter{}
	
	// 添加事件监听器
	emitter.On("user.created", func(ev *emitter.Event) {
		fmt.Printf("新用户创建: %v\n", ev.Args[0])
	})
	
	// 触发事件
	emitter.Emit("user.created", "John Doe")
}

2. 多事件监听

emitter.On("user.created", func(ev *emitter.Event) {
    fmt.Println("处理程序1:", ev.Args[0])
})

emitter.On("user.created", func(ev *emitter.Event) {
    fmt.Println("处理程序2:", ev.Args[0])
})

emitter.Emit("user.created", "Alice")
// 输出:
// 处理程序1: Alice
// 处理程序2: Alice

3. 一次性事件监听

// 只监听一次
once := emitter.Once("user.login", func(ev *emitter.Event) {
    fmt.Println("用户登录:", ev.Args[0])
})

emitter.Emit("user.login", "Bob") // 触发
emitter.Emit("user.login", "Bob") // 不会触发

// 可以取消一次性监听
once.Off()

4. 取消事件监听

// 添加监听器
listener := emitter.On("message.received", func(ev *emitter.Event) {
    fmt.Println("收到消息:", ev.Args[0])
})

// 取消监听
listener.Off()

emitter.Emit("message.received", "Hello") // 不会触发

高级功能

1. 通配符监听

// 监听所有以"user."开头的事件
emitter.On("user.*", func(ev *emitter.Event) {
    fmt.Printf("用户事件 %s: %v\n", ev.OriginalTopic, ev.Args[0])
})

emitter.Emit("user.created", "Charlie")
emitter.Emit("user.deleted", "Dave")

2. 并发安全

emitter是并发安全的,可以在goroutine中使用:

go func() {
    emitter.On("data.ready", func(ev *emitter.Event) {
        fmt.Println("数据已准备好:", ev.Args[0])
    })
}()

go func() {
    emitter.Emit("data.ready", 42)
}()

3. 限制监听器数量

// 只保留最近的3个监听器
emitter := emitter.Emitter{Cap: 3}

for i := 0; i < 5; i++ {
    emitter.On("event", func(ev *emitter.Event) {
        fmt.Println("处理事件:", ev.Args[0])
    })
}

// 只有最后3个监听器会被保留

实际应用示例

package main

import (
	"fmt"
	"time"
	"github.com/olebedev/emitter"
)

type User struct {
	ID   int
	Name string
}

func main() {
	eventBus := emitter.Emitter{}
	
	// 用户服务
	go func() {
		eventBus.On("user.register", func(ev *emitter.Event) {
			user := ev.Args[0].(User)
			fmt.Printf("注册新用户: %s (ID: %d)\n", user.Name, user.ID)
			
			// 触发后续事件
			eventBus.Emit("user.registered", user)
			eventBus.Emit("email.welcome", user)
		})
	}()
	
	// 邮件服务
	go func() {
		eventBus.On("email.welcome", func(ev *emitter.Event) {
			user := ev.Args[0].(User)
			fmt.Printf("发送欢迎邮件给: %s <%d@example.com>\n", user.Name, user.ID)
		})
	}()
	
	// 日志服务
	go func() {
		eventBus.On("*", func(ev *emitter.Event) {
			fmt.Printf("[LOG] 事件: %s, 参数: %v\n", ev.OriginalTopic, ev.Args)
		})
	}()
	
	// 模拟用户注册
	eventBus.Emit("user.register", User{ID: 1, Name: "John"})
	
	// 等待事件处理完成
	time.Sleep(100 * time.Millisecond)
}

注意事项

  1. 事件参数通过ev.Args访问,它是一个[]interface{}类型
  2. 通配符监听可能会影响性能,谨慎使用
  3. 确保在不需要时取消事件监听,避免内存泄漏
  4. 对于高频事件,考虑使用带缓冲的通道模式

emitter库提供了一种简单而强大的方式来实现Go程序中的事件驱动架构,特别适合需要解耦组件通信的场景。

回到顶部