Documentation ¶
Overview ¶
Package js the JavaScript implementation
Index ¶
- Constants
- Variables
- func EnableConsole(vm *goja.Runtime)
- func EnableRequire(vm *goja.Runtime, path ...string)
- func Format(call goja.FunctionCall, vm *goja.Runtime) goja.Value
- func InitGlobalModule(runtime *goja.Runtime)
- func NewPromise(runtime *goja.Runtime, asyncFunc func() (any, error)) *goja.Promise
- func Run(ctx context.Context, p Program) (goja.Value, error)
- func RunString(ctx context.Context, script string) (goja.Value, error)
- func SetOptions(opt Options)
- func Throw(vm *goja.Runtime, err error)
- func ToBytes(data any) ([]byte, error)
- func ToStrings(data any) (s any, err error)
- func Unwrap(value goja.Value) (any, error)
- func VMContext(runtime *goja.Runtime) context.Context
- type Cat
- func (c *Cat) Cancel()
- func (c *Cat) ClearVar()
- func (c *Cat) GetElement(key string, rule string, content any) (ret string, err error)
- func (c *Cat) GetElements(key string, rule string, content any) (ret []string, err error)
- func (c *Cat) GetString(key string, rule string, content any) (ret string, err error)
- func (c *Cat) GetStrings(key string, rule string, content any) (ret []string, err error)
- func (c *Cat) GetVar(call goja.FunctionCall, vm *goja.Runtime) goja.Value
- func (c *Cat) Log(call goja.FunctionCall, vm *goja.Runtime) goja.Value
- func (c *Cat) SetVar(key string, value goja.Value) error
- type EnqueueCallback
- type EventLoop
- type FieldNameMapper
- type Options
- type Program
- type Scheduler
- type VM
Constants ¶
const ( // DefaultMaxTimeToWaitGetVM default retries time DefaultMaxTimeToWaitGetVM = 500 * time.Millisecond // DefaultMaxRetriesGetVM default retries times DefaultMaxRetriesGetVM = 3 )
Variables ¶
var ( // ErrInvalidModule module is invalid ErrInvalidModule = errors.New("invalid module") // ErrIllegalModuleName module name is illegal ErrIllegalModuleName = errors.New("illegal module name") // ErrModuleFileDoesNotExist module not exist ErrModuleFileDoesNotExist = errors.New("module file does not exist") )
var ( // ErrSchedulerClosed the scheduler is closed error ErrSchedulerClosed = errors.New("scheduler is closed") )
Functions ¶
func EnableRequire ¶ added in v0.4.0
EnableRequire set runtime require module
func InitGlobalModule ¶ added in v0.4.0
InitGlobalModule init all global modules
func NewPromise ¶ added in v0.4.1
NewPromise returns the new promise with the async function. must be called on the EventLoop. like this:
func main() { vm := js.NewVM() ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() goFunc := func(call goja.FunctionCall, vm *goja.Runtime) goja.Value { return vm.ToValue(js.NewPromise(vm, func() (any, error) { time.Sleep(time.Second) return call.Argument(0).ToInteger() + call.Argument(1).ToInteger(), nil })) } _ = vm.Runtime().Set("asyncAdd", goFunc) start := time.Now() result, err := vm.RunString(ctx, `asyncAdd(1, 2)`) if err != nil { panic(err) } value, err := js.Unwrap(result) if err != nil { panic(err) } fmt.Println(value) fmt.Println(time.Now().Sub(start)) }
func SetOptions ¶ added in v0.4.0
func SetOptions(opt Options)
SetOptions set the default js Options.
func ToStrings ¶ added in v0.4.0
ToStrings tries to return a string slice or string from compatible types.
Types ¶
type Cat ¶
Cat an analyzer context
func (*Cat) Cancel ¶
func (c *Cat) Cancel()
Cancel this context releases resources associated with it, so code should call cancel as soon as the operations running in this Context complete.
func (*Cat) GetElement ¶
GetElement gets the string of the content with the given arguments
func (*Cat) GetElements ¶
GetElements gets the string of the content with the given arguments
func (*Cat) GetStrings ¶
GetStrings gets the string of the content with the given arguments
func (*Cat) GetVar ¶
GetVar returns the value associated with this context for key, or nil if no value is associated with key.
type EnqueueCallback ¶ added in v0.4.1
type EnqueueCallback func(func() error)
func NewEnqueueCallback ¶ added in v0.4.2
func NewEnqueueCallback(runtime *goja.Runtime) EnqueueCallback
NewEnqueueCallback signals to the event loop that you are going to do some asynchronous work off the main thread and that you may need to execute some code back on the main thread when you are done. see EventLoop.RegisterCallback.
func doAsyncWork(runtime *goja.Runtime) *goja.Promise { enqueueCallback := js.NewEnqueueCallback(runtime) promise, resolve, reject := runtime.NewPromise() // Do the actual async work in a new independent goroutine, but make // sure that the Promise resolution is done on the main thread: go func() { // Also make sure to abort early if the context is cancelled, so // the VM is not stuck when the scenario ends or Ctrl+C is used: result, err := doTheActualAsyncWork() enqueueCallback(func() error { if err != nil { reject(err) } else { resolve(result) } return nil // do not abort the iteration }) }() return promise }
type EventLoop ¶ added in v0.4.1
type EventLoop struct {
// contains filtered or unexported fields
}
EventLoop implements an event with handling of unhandled rejected promises.
A specific thing about this event loop is that it will wait to return not only until the queue is empty but until nothing is registered that it will run in the future. This is in contrast with more common behaviours where it only returns on a specific event/action or when the loop is empty. This is required as in k6 iterations (for which event loop will be primary used) are supposed to be independent and any work started in them needs to finish, but also they need to end when all the instructions are done. Additionally because of this on any error while the event loop will exit it's required to wait on the event loop to be empty before the execution can continue.
func NewEventLoop ¶ added in v0.4.1
NewEventLoop returns a new event loop with a few helpers attached to it: - adding setTimeout javascript implementation - reporting (and aborting on) unhandled promise rejections
func (*EventLoop) RegisterCallback ¶ added in v0.4.1
func (e *EventLoop) RegisterCallback() EnqueueCallback
RegisterCallback signals to the event loop that you are going to do some asynchronous work off the main thread and that you may need to execute some code back on the main thread when you are done. So, once you call this method, the event loop will wait for you to finish and give it the callback it needs to run back on the main thread before it can end the whole current script iteration.
RegisterCallback() *must* be called from the main runtime thread, but its result enqueueCallback() is thread-safe and can be called from any goroutine. enqueueCallback() ensures that its callback parameter is added to the VM runtime's tasks queue, to be executed on the main runtime thread eventually, when the VM is done with the other tasks before it. Unless the whole event loop has been stopped, invoking enqueueCallback() will queue its argument and "wake up" the loop (if it was idle, but not stopped).
Keep in mind that once you call RegisterCallback(), you *must* also call enqueueCallback() exactly once, even if don't actually need to run any code on the main thread. If that's the case, you can pass an empty no-op callback to it, but you must call it! The event loop will wait for the enqueueCallback() invocation and the k6 iteration won't finish and will be stuck until the VM itself has been stopped (e.g. because the whole test or scenario has ended). Any error returned by any callback on the main thread will abort the current iteration and no further event loop callbacks will be executed in the same iteration.
A common pattern for async work is something like this:
func doAsyncWork(vm js.VM) *goja.Promise { enqueueCallback := vm.Runtime().GlobalObject().GetSymbol(enqueueCallbackSymbol).Export().(func() EnqueueCallback)() p, resolve, reject := vm.Runtime().NewPromise() // Do the actual async work in a new independent goroutine, but make // sure that the Promise resolution is done on the main thread: go func() { // Also make sure to abort early if the context is cancelled, so // the VM is not stuck when the scenario ends or Ctrl+C is used: result, err := doTheActualAsyncWork() enqueueCallback(func() error { if err != nil { reject(err) } else { resolve(result) } return nil // do not abort the iteration }) }() return p }
This ensures that the actual work happens asynchronously, while the Promise is immediately returned and the main thread resumes execution. It also ensures that the Promise resolution happens safely back on the main thread once the async work is done, as required by goja and all other JS runtimes.
TODO: rename to ReservePendingCallback or something more appropriate?
func (*EventLoop) Start ¶ added in v0.4.1
Start will run the event loop until it's empty and there are no uninvoked registered callbacks or a queued function returns an error. The provided firstCallback will be the first thing executed. After Start returns the event loop can be reused as long as waitOnRegistered is called.
func (*EventLoop) WaitOnRegistered ¶ added in v0.4.1
func (e *EventLoop) WaitOnRegistered()
WaitOnRegistered waits on all registered callbacks so we know nothing is still doing work. This does call back the callbacks and more can be queued over time. A different mechanism needs to be used to tell the users that the event loop has errored out or winding down for a different reason.
type FieldNameMapper ¶ added in v0.4.0
type FieldNameMapper struct{}
FieldNameMapper provides custom mapping between Go and JavaScript property names.
func (FieldNameMapper) FieldName ¶ added in v0.4.0
func (FieldNameMapper) FieldName(_ reflect.Type, f reflect.StructField) string
FieldName returns a JavaScript name for the given struct field in the given type. If this method returns "" the field becomes hidden.
func (FieldNameMapper) MethodName ¶ added in v0.4.0
MethodName returns a JavaScript name for the given method in the given type. If this method returns "" the method becomes hidden.
type Options ¶
type Options struct { InitialVMs int `yaml:"initial-vms"` MaxVMs int `yaml:"max-vms"` MaxRetriesGetVM int `yaml:"max-retries-get-vm"` MaxTimeToWaitGetVM time.Duration `yaml:"max-time-to-wait-get-vm"` ModulePath []string `yaml:"module-path"` }
Options Scheduler options
type Scheduler ¶
type Scheduler interface { // Get the VM Get() (VM, error) // Release the VM Release(VM) // Close the scheduler Close() error }
Scheduler the VM scheduler
type VM ¶
type VM interface { // Run the js program Run(context.Context, Program) (goja.Value, error) // RunString the js string RunString(context.Context, string) (goja.Value, error) // Runtime the js runtime Runtime() *goja.Runtime }
VM the js runtime. An instance of VM can only be used by a single goroutine at a time.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
cache
Package cache the cache JS implementation
|
Package cache the cache JS implementation |
cookie
Package cookie the cookie JS implementation
|
Package cookie the cookie JS implementation |
crypto
Package crypto the crypto JS implementation
|
Package crypto the crypto JS implementation |
encoding
Package encoding the encoding JS implementation
|
Package encoding the encoding JS implementation |
http
Package http the http JS implementation
|
Package http the http JS implementation |
Package modulestest the module test vm
|
Package modulestest the module test vm |