go: syscall/js: deadlock occurred with http.Get

What version of Go are you using (go version)?

go version devel +4eb1c84752 Fri Jun 15 02:09:44 2018 +0000 darwin/amd64

Does this issue reproduce with the latest release?

It has occurred with 4eb1c84752b8d3171be930abf4281080d639f634.

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/tenntenn/Library/Caches/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/tenntenn/Documents/gopath"
GORACE=""
GOROOT="/usr/local/gotip"
GOTMPDIR=""
GOTOOLDIR="/usr/local/gotip/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/mq/m9_twy8j1vl9ppr6j5xqtfq80000gn/T/go-build130694127=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

I built this code withGOOS=js GOARCH=wasm.

package main

import (
	"fmt"
	"net/http"
	"syscall/js"
)

func main() {
	var cb js.Callback
	cb = js.NewCallback(func(args []js.Value) {
		fmt.Println("Clicked")
		resp, err := http.Get("/")
		fmt.Println(resp, err)
	})
	js.Global.Get("document").Call("getElementById", "btn").Call("addEventListener", "click", cb)
	select {}
}

And I ran it on Chrome using misc/wasm/wasm_exec.js and misc/wasm/wasm_exec.html. In addition, I added a button to wasm_exec.html.

It occurred deadlock.

fatal error: all goroutines are asleep - deadlock!
wasm_exec.js:39 
wasm_exec.js:39 goroutine 1 [select (no cases)]:
wasm_exec.js:39 main.main()
wasm_exec.js:39 	/path/to/dir/main.go:17 +0x7
wasm_exec.js:39 
wasm_exec.js:39 goroutine 5 [select]:
wasm_exec.js:39 net/http.(*Transport).RoundTrip(0x312b20, 0xc0d8000, 0x0, 0x0, 0x0)
wasm_exec.js:39 	/usr/local/gotip/src/net/http/roundtrip_js.go:123 +0x40
wasm_exec.js:39 net/http.send(0xc0d8000, 0xaa5a0, 0x312b20, 0x0, 0x0, 0x0, 0xc00c058, 0xf8, 0xc028ba0, 0x1)
wasm_exec.js:39 	/usr/local/gotip/src/net/http/client.go:252 +0x16
wasm_exec.js:39 net/http.(*Client).send(0x31ebc0, 0xc0d8000, 0x0, 0x0, 0x0, 0xc00c058, 0x0, 0x1, 0x6bfa0)
wasm_exec.js:39 	/usr/local/gotip/src/net/http/client.go:176 +0x10
wasm_exec.js:39 net/http.(*Client).Do(0x31ebc0, 0xc0d8000, 0x7468c, 0x1, 0x0)
wasm_exec.js:39 	/usr/local/gotip/src/net/http/client.go:615 +0x16
wasm_exec.js:39 net/http.(*Client).Get(0x31ebc0, 0x7468c, 0x1, 0x8, 0x0, 0x0)
wasm_exec.js:39 	/usr/local/gotip/src/net/http/client.go:396 +0x5
wasm_exec.js:39 net/http.Get(0x7468c, 0x1, 0x1, 0x8, 0x0)
wasm_exec.js:39 	/usr/local/gotip/src/net/http/client.go:370 +0x2
wasm_exec.js:39 main.main.func1(0xc01e280, 0x1, 0x1)
wasm_exec.js:39 	/path/to/dir/main.go:13 +0x3
wasm_exec.js:39 syscall/js.callbackLoop()
wasm_exec.js:39 	/usr/local/gotip/src/syscall/js/callback.go:139 +0x6
wasm_exec.js:39 created by syscall/js.NewCallback.func1
wasm_exec.js:39 	/usr/local/gotip/src/syscall/js/callback.go:65 +0x2

I tried to remove select{} but it immediately exit and it didn’t kick the callback.

Uncaught Error: bad callback: Go program has already exited
    at _values (wasm_exec.js:305)
    at HTMLButtonElement.eval (eval at syscall/js.valueCall (wasm_exec.js:222), <anonymous>:5:4)

What did you expect to see?

Any errors do not occur with a click event and http.Get.

What did you see instead?

It occurred an error.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 15 (15 by maintainers)

Most upvoted comments

The problem is that you are blocking the callback loop. New calls to callbacks (like the HTTP response) can not be processed while some other callback handler (like the click handler) have not returned. You need to explicitly start a new goroutine:

package main

import (
	"fmt"
	"net/http"
	"syscall/js"
)

func main() {
	var cb js.Callback
	done := make(chan struct{})
	cb = js.NewCallback(func(args []js.Value) {
		go func() {
			fmt.Println("Clicked")
			resp, err := http.Get("/")
			fmt.Println(resp, err)
			close(done)
		}()
	})
	js.Global.Get("document").Call("getElementById", "btn").Call("addEventListener", "click", cb)
	<-done
}