v8go
v8go copied to clipboard
How to construct an array and pass it in through global
I could not find any documentation how to construct an array and pass it in through global.
Currently not supported by the Go API, but you can create a array on the JS side and attach it to the global object. I'm looking to add support for this from Go soon.
What I ended up doing was just faking it with the object where I set numeric properties. Worked for my limited use case.
I have an interest in array support as well.
it should be actually rather simple:
type Array struct {
*Object
}
func NewArray(ctx *ExecContext, len int64) *Array {
val := &Value{C.NewArray(ctx.iso.ptr, C.size_t(len)), ctx}
return &Array{Object: &Object{Value: val}}
}
// Create a new NewArray value of the requested size
ValuePtr NewArray(IsolatePtr iso_ptr, size_t length) {
ISOLATE_SCOPE_INTERNAL_CONTEXT(iso_ptr);
Local<Context> c = ctx->ptr.Get(iso);
c->Enter();
Local<Array> arr = Array::New(iso, length);
m_value* val = new m_value;
val->iso = iso;
val->ctx = ctx;
val->ptr = Persistent<Value, CopyablePersistentTraits<Value>>(iso, arr);
return tracked_value(ctx, val);
}
should do it, since Array is an object, Set()
is available.
I have found a way to do this without object template:
// first at all, we create a new Array
arrayValue, err := ctx.RunScript("new Array()", "")
if err != nil {
return nil, err
}
var obj = arrayValue.Object()
// set array elements count
err = obj.Set("length", 10)
if err != nil {
return nil, err
}
// we add elements to the array
obj.SetIdx(0, "value1")
obj.SetIdx(1, "value2")
...
// now, the resultArray is you wanted
var resultArray = obj.Value
Probably the number one lacking feature.
workarounds are nice, kind of surprised it isn't part of the default API though
v8::Array::New is an overloaded function, so we should consider how we want to expose the two ways it can be called. It looks like they correspond to the JS Array constructors.
One function creates an array with provided values. It seems like this would map well to variadic functions func NewArray(values ...v8go.Valuer) Array
. Or is there a concern with efficiency with passing a large Go slice like this as variadic arguments? If there ends up being problems with efficiency with variadic arguments, we could always extract the implementation into func NewArrayFromSlice(values []v8go.Value) Array
as an alternative.
The other function creates an array of a given length without initializing the values. Perhaps this could be NewArrayWithLength(length uint32) Array
.
@huttarichard you had named this function NewArray in your comment, is that because you believe this would be more commonly used? It seems like the variadic function corresponds more closely corresponds with creating a literal Array, which seemed like it was more deserving of brief usage.
Does anyone else have opinions on the v8go API for constructing an array?
@dylanahsmith Have you thought about adding slice/array support to the v8go.NewValue
method? I think this would provide the best developer experience. This was also the first place I looked at, while trying to find out how to create a JS array via Go.
hello, _ := v8go.NewValue(iso, "hello")
world, _ := v8go.NewValue(iso, "world")
_, _ = v8go.NewValue(iso, []string{"hello", "world"})
_, _ = v8go.NewValue(iso, []*v8.Value{hello, world})
Once there is a NewArrayFromSlice-like function, then NewValue could delegate to it.
However, NewValue suffers from a lack of type safety, which can lead to a lack of clarity on where errors may be returned. This can lead to errors being ignored, which makes debugging more difficult or to verbose unused error handling code. Even when it is known that the error isn't needed, an assignment is needed to ignore the error rather than allowing the value to be used directly. The more general v8go.Value type also gets returned, which can lead to a dynamic cast to be needed, which also returns an error.
You're right, but the addition of slice support for NewValue wouldn't make it worse, as the type safety problems already exist. Maybe NewValue should be deprecated and specialized methods for every type should be added.
func NewStringValue(s string) *v8go.Value
func NewIntValue(i int) *v8go.Value
@iwind , I dig the idea of using javascript to build on v8go, so I generified your idea a little as a workaround to support http.Header
. Though I, too, would very much enjoy native support, @dylanahsmith . I wonder how bad the performance of JSON.parse
will impact.
func parseToValue(vm *v8.Isolate, in interface{}) (*v8.Value, error) {
bytes, err := json.Marshal(in)
if err != nil {
return nil, err
}
ctx := v8.NewContext(vm)
res, err := ctx.RunScript(fmt.Sprintf("JSON.parse(`%s`)", string(bytes)), "parse_to_value")
if err != nil {
return nil, err
}
return res.Object().Value, err
}