Promise的Golang实现,其行为符合Promises/A+规范,并参考Promise ES规范实现,尽可能模拟了JavaScript事件循环中Promise的行为。
Promise-Go提供了一个完整的异步编程解决方案,允许开发者以链式调用的方式处理异步操作,具有以下特点:
- 完全符合
Promises/A+规范 - 支持
Promise ES规范中的常用方法 - 模拟
JavaScript事件循环机制(宏任务和微任务队列) - 提供丰富的
Promise组合方法(All、AllSettled、Any、Race等) - 实现
Stringer接口,支持直接打印Promise实例状态 - 提供定时器相关功能(
SetTimeout、SetInterval等)
以下是一个简单的示例,展示如何创建和使用Promise:
使用Go模块系统安装Promise-Go:
go get github.com/TikaFlow/promise-goimport "github.com/TikaFlow/promise-go"package main
import "github.com/TikaFlow/promise-go"
func main() {
// 推荐将 Promise 相关代码包装为异步任务,更符合事件循环机制
promise.Async(func() {
// 创建一个成功的 Promise
p := promise.New(func(resolve, reject func(v any)) (err error) {
// 模拟异步操作
promise.SetTimeout(func() {
resolve("操作成功完成")
}, 1000)
return
})
// 处理 Promise
p.Then(func(v any) (any, error) {
println("成功:", v.(string))
return v, nil
}, func(reason any) (any, error) {
println("失败:", reason)
return nil, nil
})
})
// 等待事件循环结束,避免 main 函数提前退出
<-promise.Done()
}请参考API文档获取完整的函数列表和详细说明。
// Promise 是一个拥有 then 方法的对象,其行为符合 Promises/A+ 规范
type Promise interface {
// State 返回 Promise 的当前状态
State() string
// Result 返回 Promise 的结果值
Result() any
// Done 返回一个通道,当 Promise 状态变为 Fulfilled 或 Rejected 时,该通道会被关闭
Done() chan struct{}
// Then 方法返回一个新的 Promise,其状态和结果值由回调函数的执行结果决定
Then(onFulfilled, onRejected ThenCallback) Promise
// Catch 方法返回一个新的 Promise,是 Then(nil, onRejected) 的语法糖
Catch(onRejected ThenCallback) Promise
// Finally 方法返回一个新的 Promise,其状态和结果值与原 Promise 相同
Finally(onFinally FinallyCallback) Promise
}// New 创建一个新的 Promise 实例
func New(exec Executor) Promise
// Resolve 返回一个已解决的 Promise
func Resolve(value any) Promise
// Reject 返回一个已拒绝的 Promise
func Reject(reason any)// All 等待所有 Promise 解决
func All(proms ...any) Promise
// AllSettled 等待所有 Promise 完成(无论成功失败)
func AllSettled(proms ...any) Promise
// Any 等待第一个 Promise 解决
func Any(proms ...any) Promise
// Race 等待第一个 Promise 完成
func Race(proms ...any) Promise// 创建一个立即解决的 Promise
p := promise.New(func(resolve, reject func(v any)) (err error) {
resolve("hello world")
return
})p := promise.New(func(resolve, reject func(v any)) (err error) {
resolve("hello world")
return
})
p.Then(func(v any) (any, error) {
println(v.(string)) // 输出: hello world
return v, nil
}, nil).Then(func(v any) (any, error) {
println(v.(string)) // 输出: hello world
return v, nil
}, nil).Catch(func(err any) (any, error) {
println("捕获到错误:", err)
return nil, nil
}).Finally(func() (any, error) {
println("无论成功失败都会执行")
return nil, nil
})更多完整的示例可以参考项目中的示例文件:
在长时间运行的程序中,应首先调用EventLoopHandler()获取事件循环句柄,以免事件循环因空闲超时而被动退出。
并在程序结束前调用该句柄的Close()方法主动结束事件循环。
如果不需要长时间运行,或不需要主动结束事件循环,则可以不调用EventLoopHandler(),
而是通过Done()获取关闭信号的通道,等待通道关闭。
// 短时间运行的程序,无需主动关闭事件循环
func main() {
// 创建一个 Promise
p := promise.New(func(resolve, reject func(v any)) (err error) {
// 模拟异步操作
promise.SetTimeout(func() {
resolve("操作完成")
}, 2000)
return
})
// 等待事件循环关闭
<-promise.Done()
println("Promise 完成")
}
// 长时间运行的程序,建议主动关闭事件循环
func main() {
// 获取事件循环句柄
elh := promise.EventLoopHandler()
// 关闭事件循环
defer elh.Close()
// 长时间服务循环
service()
}默认情况下,事件循环的超时时间为512毫秒,并有128毫秒的额外超时保护,即共计640毫秒。如果一个异步任务在640毫秒内未完成, 或空闲时间超过640毫秒,事件循环会被强制退出。
可以通过以下方式延长:
- 【推荐】获取事件循环操作句柄:将无限延长超时时间(即永不超时),直到手动关闭事件循环。
- 手动延长超时时间:调用
promise.SetTimeout()或promise.SetInterval()时,将根据设置的延迟时间自动延长超时时间(一次有效,到期将恢复)。
<-p.Done()可以等待Promise完成,但需要注意,这会阻塞当前goroutine,直到Promise完成(有可能永远是Pending)。因此应避免使用,
而是使用p.Then()或p.Catch()来处理Promise的结果,或调用promise.Await()等待Promise完成。
Promise链中的错误会自动传播到下一个拒绝处理程序。与在JS中一样,可以在链的末端添加.Catch()以捕获任何未处理的错误。
由于Go的类型系统,在处理Promise结果时需要进行类型断言。请确保安全地处理断言可能失败的情况。
p.Then(func(v any) (any, error) {
// 安全地进行类型断言
if str, ok := v.(string); ok {
println("字符串结果:", str)
} else {
println("类型错误,不是字符串")
}
return v, nil
}, nil)ThenCallback和FinallyCallback回调函数中,如果有报错,请务必将错误信息放入在v中,并在err中放入简单错误信息(也不能为nil)。
这是为了支持任意类型的错误信息,即此时应该返回(detail, summary)格式的错误,而不是(nil, err)。
定时器(SetTimeout/SetInterval)的精度依赖于Go运行时和系统调度,不保证毫秒级精确执行及执行顺序。
大量的微任务或宏任务可能会影响性能,特别是在高并发场景下。请合理使用这些功能。
在Then(及Catch、Finally)回调中使用不正确的报错方式(即返回(nil, err)而不是(detail, summary))会导致后续的Promise链接收nil。
在Promise执行器或回调中执行耗时操作会阻塞整个事件循环,应避免这样做。
过多的Promise嵌套会使代码难以理解和维护。尽量使用链式调用或组合函数来扁平化异步流程。
MIT License
Copyright (c) [2025] [兮夏]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.