Documentation
¶
Overview ¶
Package eventloop provides an event loop implementation for running asynchronous JavaScript code with Goja. It enables async/await and Promise support in custom JavaScript functions by processing the microtask queue.
The design is inspired by Grafana k6's event loop implementation and goja_nodejs.
Index ¶
- Variables
- func ExtractPromiseValue(value goja.Value) (interface{}, error)
- func GetPromise(value goja.Value) *goja.Promise
- func IsPromise(value goja.Value) bool
- type EventLoop
- func (e *EventLoop) AwaitPromise(ctx context.Context, value goja.Value) PromiseResult
- func (e *EventLoop) ClearTimeout(t *Timer)
- func (e *EventLoop) EnqueueJob(fn func())
- func (e *EventLoop) NewPromise() (*goja.Promise, func(interface{}), func(interface{}))
- func (e *EventLoop) RegisterCallback() func(func())
- func (e *EventLoop) RegisterFetch(config *fetch.FetchConfig)
- func (e *EventLoop) Run(ctx context.Context, fn func(*goja.Runtime) (goja.Value, error)) (goja.Value, error)
- func (e *EventLoop) RunOnLoop(fn func()) bool
- func (e *EventLoop) Runtime() *goja.Runtime
- func (e *EventLoop) SetTimeout(fn func(), delay time.Duration) *Timer
- func (e *EventLoop) WrapGoFunctionAsync(name string, fn func(call goja.FunctionCall, enqueue func(func())) goja.Value)
- type PromiseResult
- type PromiseState
- type Timer
Constants ¶
This section is empty.
Variables ¶
var ( // ErrLoopAlreadyRunning is returned when Run is called on an already running loop ErrLoopAlreadyRunning = errors.New("event loop already running") // ErrLoopNotRunning is returned when trying to queue work on a stopped loop ErrLoopNotRunning = errors.New("event loop not running") // ErrPromiseRejected is returned when a Promise is rejected ErrPromiseRejected = errors.New("promise rejected") // ErrPromiseTimeout is returned when a Promise doesn't resolve within timeout ErrPromiseTimeout = errors.New("promise did not resolve within timeout") )
Functions ¶
func ExtractPromiseValue ¶
ExtractPromiseValue extracts the resolved value from a Promise. If the value is not a Promise, returns the value directly. Returns an error if the Promise was rejected or is still pending.
func GetPromise ¶
GetPromise extracts a *goja.Promise from a goja.Value Returns nil if the value is not a Promise
Types ¶
type EventLoop ¶
type EventLoop struct {
// contains filtered or unexported fields
}
EventLoop manages asynchronous JavaScript execution by processing a job queue and handling Promise microtasks.
func New ¶
New creates a new EventLoop wrapping the given Goja runtime. The runtime should not be used directly while the event loop is running.
func (*EventLoop) AwaitPromise ¶
AwaitPromise waits for a Promise to resolve or reject. It processes the event loop until the Promise settles or the context is cancelled.
If the value is not a Promise, it returns immediately with the value.
func (*EventLoop) ClearTimeout ¶
ClearTimeout cancels a pending timeout created with SetTimeout
func (*EventLoop) EnqueueJob ¶
func (e *EventLoop) EnqueueJob(fn func())
EnqueueJob adds a job to the queue. Thread-safe: can be called from any goroutine.
func (*EventLoop) NewPromise ¶
NewPromise creates a new Promise and returns resolve/reject functions. This is a convenience wrapper around goja.Runtime.NewPromise().
func (*EventLoop) RegisterCallback ¶
func (e *EventLoop) RegisterCallback() func(func())
RegisterCallback returns a function that will queue work on the event loop. This is the k6-style pattern for async operations.
When called, it increments the pending operation counter to prevent the loop from exiting. The returned function should be called with the callback to execute when the async operation completes.
func (*EventLoop) RegisterFetch ¶
func (e *EventLoop) RegisterFetch(config *fetch.FetchConfig)
RegisterFetch registers the fetch() function in the JavaScript runtime. If config is nil, secure defaults are used (HTTPS only, no private networks).
func (*EventLoop) Run ¶
func (e *EventLoop) Run(ctx context.Context, fn func(*goja.Runtime) (goja.Value, error)) (goja.Value, error)
Run executes the provided function and processes the event loop until all pending work completes or the context is cancelled.
The function fn is called with the Goja runtime and should return the result of the JavaScript execution (which may be a Promise).
Run blocks until:
- All pending jobs are processed, and no more work is queued
- The context is cancelled (timeout or explicit cancellation)
- An error occurs during execution
func (*EventLoop) RunOnLoop ¶
RunOnLoop queues a function to be executed on the event loop. This is thread-safe and can be called from any goroutine. Returns false if the loop is not running.
func (*EventLoop) Runtime ¶
Runtime returns the underlying Goja runtime. Should only be used when the loop is not running.
func (*EventLoop) SetTimeout ¶
SetTimeout schedules a Go function to be called after the specified delay. Returns a Timer that can be used with ClearTimeout.
func (*EventLoop) WrapGoFunctionAsync ¶
func (e *EventLoop) WrapGoFunctionAsync(name string, fn func(call goja.FunctionCall, enqueue func(func())) goja.Value)
WrapGoFunctionAsync wraps a Go function as an async JavaScript function. The Go function receives the event loop's RegisterCallback function to properly signal async completion.
Example usage:
loop.WrapGoFunctionAsync("fetchData", func(call goja.FunctionCall, enqueue func(func())) goja.Value {
url := call.Argument(0).String()
promise, resolve, reject := loop.vm.NewPromise()
go func() {
result, err := http.Get(url)
enqueue(func() {
if err != nil {
reject(loop.vm.NewGoError(err))
} else {
resolve(loop.vm.ToValue(result))
}
})
}()
return loop.vm.ToValue(promise)
})
type PromiseResult ¶
type PromiseResult struct {
State PromiseState
Value goja.Value
Error error
}
PromiseResult holds the result of awaiting a Promise
type PromiseState ¶
type PromiseState int
PromiseState represents the state of a Promise
const ( PromiseStatePending PromiseState = iota PromiseStateFulfilled PromiseStateRejected )