Open jcbhmr opened 2 months ago
Related Issues and Documentation
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
That issue https://github.com/golang/go/issues/28911 that @gabyhelp linked is kinda what I want but it went unresolved. https://go-review.googlesource.com/c/go/+/150917 which was spawned from the issue linked was abandoned. The reasoning given seemed to be of the "this doesn't belong in the standard library" vibe.
I am a bit wary of adding new API like this. We can already achieve this by manually calling the "then" function ourselves, which the net/http library already does.
This is just syntactic sugar and I am afraid might add precedent for adding more helpers like this.
I'm in the same boat: I think this is API creep. And I (now) feel the same about https://go-review.googlesource.com/c/go/+/144384/, particularly if we start citing that as precedent for changes like this.
I think that a .Await()
or something to get the await
JavaScript keyword algorithm available to Go code is a good idea. Await is similar to but not identical to just calling .then()
; there's the Promise.resolve()
native-ification step too. Related reading: https://www.zhenghao.io/posts/await-vs-promise
CC @golang/js
I'm not sure why this isn't just equivalent to calling .then
like this:
func await(awaitable js.Value) (ret js.Value, ok bool) {
ch := make(chan struct{})
go func() {
awaitable.
Call("then", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
ret = args[0]
ok = true
close(ch)
return nil
})).
Call("catch", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
ret = args[0]
ok = false
close(ch)
return nil
}))
}()
<-ch
return
}
(From a project I did in Go WASM.)
Yes, using await
and .then
are different experiences in JavaScript, but from the Go side, why wouldn't this be sufficient?
If we really want such an API, maybe we also need some new APIs like syscall/js.AsyncFuncOf()
? Considering the contagious nature of async in js, this might be necessary.
And, as there is no distinction between synchronous and asynchronous functions in Go, we may need additional wrapping to do this.
re @earthboundkid
Yes, using await and .then are different experiences in JavaScript, but from the Go side, why wouldn't this be sufficient?
This is kinda my point. The func await(awaitable)
example is experiencably different than the JS await
behaviour: it panics if awaitable
is not .then()
-able or only implements the 2-arg .then()
without a .catch()
helper. There's quite a few edge cases like that that differ among so many people creating the same helper function that are oh-so-similar but subtly different in panic conditions, error conditions, non-Promise values, properly .Release()
-ing the js.Func
things, etc.. What I would like to see is a "one good builtin way to do it" to access the JS await
keyword's behavior in Go code. And since it's a keyword from the JS language syntax I figured syscall/js
is the best place to put it.
Proposal Details
Let's say I have an async JavaScript function:
Ideally I would be able to do one of these:
Creating a promise in Go code for use by JavaScript code is ok-ish (it's not great): just use the
new Promise(callback)
constructor with a Go-definedjs.Func
callback.The other direction -- unwrapping a JavaScript
Promise
instance on the Go-side by waiting for it -- is worse.Here's the algorithm for the ECMAScript 2025
Await( value )
abstract operation: https://tc39.es/ecma262/multipage/control-abstraction-objects.html#awaitIt seems like the
.Wait()
method convention is already in the standard library withsync.WaitGroup
wg.Wait()
. Here's an idea for how that might look in Go code. I'm not a Go channels wizard so this might be the completely wrong way to do this.There's already some of this promise stuff in the Go standard library https://github.com/golang/go/blob/1d0f5c478ac176fa99d0f3d6bd540e5fb422187a/src/net/http/roundtrip_js.go#L129-L245 so it seems like this is a thing that people need to do. I think that providing a
.Wait()
orAwait(v)
or something would be a good way to "one good way to do it"-ify this.