mirror of
https://github.com/golang/go.git
synced 2025-10-29 15:54:14 +00:00
runtime, sycall/js: add support for callbacks from JavaScript
This commit adds support for JavaScript callbacks back into WebAssembly. This is experimental API, just like the rest of the syscall/js package. The time package now also uses this mechanism to properly support timers without resorting to a busy loop. JavaScript code can call into the same entry point multiple times. The new RUN register is used to keep track of the program's run state. Possible values are: starting, running, paused and exited. If no goroutine is ready any more, the scheduler can put the program into the "paused" state and the WebAssembly code will stop running. When a callback occurs, the JavaScript code puts the callback data into a queue and then calls into WebAssembly to allow the Go code to continue running. Updates #18892 Updates #25506 Change-Id: Ib8701cfa0536d10d69bd541c85b0e2a754eb54fb Reviewed-on: https://go-review.googlesource.com/114197 Reviewed-by: Austin Clements <austin@google.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
5fdacfa89f
commit
e083dc6307
18 changed files with 482 additions and 49 deletions
|
|
@ -7,6 +7,7 @@
|
|||
package js_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall/js"
|
||||
"testing"
|
||||
)
|
||||
|
|
@ -144,3 +145,52 @@ func TestNew(t *testing.T) {
|
|||
t.Errorf("got %#v, want %#v", got, 42)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallback(t *testing.T) {
|
||||
c := make(chan struct{})
|
||||
cb := js.NewCallback(func(args []js.Value) {
|
||||
if got := args[0].Int(); got != 42 {
|
||||
t.Errorf("got %#v, want %#v", got, 42)
|
||||
}
|
||||
c <- struct{}{}
|
||||
})
|
||||
defer cb.Close()
|
||||
js.Global.Call("setTimeout", cb, 0, 42)
|
||||
<-c
|
||||
}
|
||||
|
||||
func TestEventCallback(t *testing.T) {
|
||||
for _, name := range []string{"preventDefault", "stopPropagation", "stopImmediatePropagation"} {
|
||||
c := make(chan struct{})
|
||||
var flags js.EventCallbackFlag
|
||||
switch name {
|
||||
case "preventDefault":
|
||||
flags = js.PreventDefault
|
||||
case "stopPropagation":
|
||||
flags = js.StopPropagation
|
||||
case "stopImmediatePropagation":
|
||||
flags = js.StopImmediatePropagation
|
||||
}
|
||||
cb := js.NewEventCallback(flags, func(event js.Value) {
|
||||
c <- struct{}{}
|
||||
})
|
||||
defer cb.Close()
|
||||
|
||||
event := js.Global.Call("eval", fmt.Sprintf("({ called: false, %s: function() { this.called = true; } })", name))
|
||||
js.ValueOf(cb).Invoke(event)
|
||||
if !event.Get("called").Bool() {
|
||||
t.Errorf("%s not called", name)
|
||||
}
|
||||
|
||||
<-c
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleNewCallback() {
|
||||
var cb js.Callback
|
||||
cb = js.NewCallback(func(args []js.Value) {
|
||||
fmt.Println("button clicked")
|
||||
cb.Close() // close the callback if the button will not be clicked again
|
||||
})
|
||||
js.Global.Get("document").Call("getElementById", "myButton").Call("addEventListener", "click", cb)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue