Thanks to visit codestin.com
Credit goes to github.com

Skip to content

xhr-http-post-json returns : "Warning: unreachable code after return statement" #1069

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
serge-hulne opened this issue Sep 29, 2021 · 10 comments
Assignees

Comments

@serge-hulne
Copy link

serge-hulne commented Sep 29, 2021

Machine used: Mac mini M1 silicon chip.
Browser used: FireFox 92.0.1
GopherJS : GopherJS 1.17.0+go1.17.1
Go version : go version go1.17 darwin/arm64

I tried the "POST" request example using xhr from: https://siongui.github.io/2016/01/21/go-xhr-http-post-json-by-gopherjs/

I get the following warning in the browser tools (client-side: FireFox):

unreachable code after return statement

and on the serve side (in terminal), the output from is:

	print(d.Title)
	print(d.Data)

is

testnone  

Apparently, the error comes from this part of the example (the call to the Post method on the client side):

	resp, err := http.Post("/post", "application/json", strings.NewReader(jsonStr))

	if err != nil {
		// handle error
		println(err)
	}
	defer resp.Body.Close()

@serge-hulne
Copy link
Author

The code of my client-side app is:

package main

import (
	"net/http"
	"strings"

	"github.com/gopherjs/gopherjs/js"
)

var JS = js.Global
var Document = JS.Get("document")

func main() {
	f := Document.Call("querySelector", "#foo")

	f.Set("class", "c1")
	f.Set("innerHTML", "<h1>Hello World</h1>")

	d := Document.Call("createElement", "Div")
	d.Set("innerHTML", "New element")
	f.Call("appendChild", d)

	b := Document.Call("createElement", "Button")
	b.Set("innerHTML", "click here")

	b.Call("addEventListener", "click", post_it)

	f.Call("appendChild", b)
}

// Utility function for testing POST requests in GopherJs:
func post_it() {

	jsonStr := `{"title":"test","data":"none"}`

	println(jsonStr)

	resp, err := http.Post("/post", "application/json", strings.NewReader(jsonStr))

	if err != nil {
		// handle error
		println(err)
	}
	defer resp.Body.Close()

}

@serge-hulne
Copy link
Author

..in other words, the app above (in Go via GopherJS) does not seem to compile to valid JavaScript when http.Post is used.

@serge-hulne
Copy link
Author

If I comment out the http.Post part, the app works as expected (but of course, it defeats the purpose):

// Utility function for testing POST requests in GopherJs:
func post_it() {

	jsonStr := `{"title":"test","data":"none"}`

	println(jsonStr)

	// resp, err := http.Post("/post", "application/json", strings.NewReader(jsonStr))

	// if err != nil {
	// 	// handle error
	// 	println(err)
	// }
	// defer resp.Body.Close()

}

@flimzy
Copy link
Member

flimzy commented Sep 29, 2021

Likely related to (and possible duplicate of?) #575

@serge-hulne
Copy link
Author

This works, though:

func Post() {

	var url = "http://localhost:8000"

	req := js.Global.Get("XMLHttpRequest").New()
	req.Call("addEventListener", "load", func() {
		println(req.Get("responseText").String())
	})
	req.Call("open", "POST", url, true)
	req.Call("send")
}

@nevkontakte
Copy link
Member

I won't have time to give it a close look until the weekend, but one possibility is that you are making a blocking call from a JavaScript event handler, which may not be correctly interacting with the goroutine scheduler.

Can you try replacing b.Call("addEventListener", "click", post_it) with b.Call("addEventListener", "click", func() { go post_it() })?

@serge-hulne
Copy link
Author

Thank you for your answer @nevkontakte. I tried your suggestion, but it I still get the same warning.

@serge-hulne
Copy link
Author

Alternatively, I suppose I could use the GopherJS wrapper around the Fetch() api to do POST requests from the client-side (instead of using XMLHttpRequest).

Are there a few examples on how to use fetch() with GopherJS() to do GET, POST requests?

@nevkontakte
Copy link
Member

nevkontakte commented Oct 3, 2021

@serge-hulne I've taken a closer look at your example. There are several places in the generated JavaScript where Firefox shows this warning, but in all cases it is benign. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Stmt_after_return has a bit more info about this warning, at its main purpose is to catch mistakes in hand-written JavaScript, but not so much in compiled code. Note that it's just a warning, not an actual error.

To be a bit more specific, this warnings seem to happen in Go functions that follow this pattern:

func doSomething() returnType {
  for {
    // Do something.
    return result
  }
}

GopherJS transpiles this into JavaScript code that looks roughly like this:

function doSomething() {
  whille(true) {
    // Do something.
    return result;
    continue; // This is the unreachable statement, but also entirely harmless.
  }
}

In reality the generated code is a bit more complicated because happens in "flattened" functions where GopherJS uses a switch-case to jump between code blocks, and this "continue" statement is needed to ensure correctness of the loop. I'll see if it's possible to change the code generation to avoid this unnecessary statement, but the only difference it'll make is a marginal decrease in the generated code size.

For you I recommend just continue using net/http and ignore the warning.

@nevkontakte nevkontakte self-assigned this Oct 3, 2021
@serge-hulne
Copy link
Author

All right. Thank you.

nevkontakte added a commit to nevkontakte/gopherjs that referenced this issue Oct 3, 2021
When GopherJS flattens a loop into a while-switch-case construct, it
needs to generate an instruction to go back to the beginning of the loop
after the last statement of the loop body. However, when the last
statement is a control statement itself (return, continue, break, goto),
this instruction becomes unnecessary and unreachable. Example Go code:

```go
func foo() {
  for {
    // Do something
    break
  }
}
```

This change prevents such an instruction from being generated. This has
a marginal artifact size reduction (1632 bytes on todomvc), but also
eliminates a warning Firefox prints in the console, which may be
confusing to users (gopherjs#1069, gopherjs#575).
nevkontakte added a commit to nevkontakte/gopherjs that referenced this issue Oct 3, 2021
The improved check is able to detect cases when the return statement is
wrapped in another statement, but is effectively the last executed
statement in a list, for example:

```go
func withGoto() (resultType, error) {
  // Do something.
  return result, nil
Error:
  return nil, err // This is inside an *ast.LabeledStmt!
}

func withBlock() resultType {
  // Do something.
  {
    // Do more.
    return result // This is inside a *ast.BlockStmt!
  }
}
```

Better detection prevents generation of unnecessary return statements at
the end of a function (marginally smaller output size), as well as
prevents "unreachable code" warnings in Firefox (gopherjs#575, gopherjs#1069).
nevkontakte added a commit to nevkontakte/gopherjs that referenced this issue Oct 3, 2021
The improved check is able to detect cases when the return statement is
wrapped in another statement, but is effectively the last executed
statement in a list, for example:

```go
func withGoto() (resultType, error) {
  // Do something.
  return result, nil
Error:
  return nil, err // This is inside an *ast.LabeledStmt!
}

func withBlock() resultType {
  // Do something.
  {
    // Do more.
    return result // This is inside a *ast.BlockStmt!
  }
}
```

Better detection prevents generation of unnecessary return statements at
the end of a function (marginally smaller output size), as well as
prevents "unreachable code" warnings in Firefox (gopherjs#575, gopherjs#1069).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants