Documentation ¶
Overview ¶
Package promise provides support for returning Promises in gopherjs.
The simplest usage is to use the Promisify() function to convert a (potentially-blocking) function call into a promise. This allows easily converting a typical synchronous (idiomatic) Go API into a promise-based (idiomatic) JS api.
For example:
func main() { js.Global.Set("whoami", promise.Promisify(whoami)) // or as part of a structed object: js.Global.Set("api", map[string]interface{}{ "whoami": promise.Promisify(whoami), }) } // This is a blocking function -- it doesn't return until the XHR // completes or fails. func whoami() (User, error) { if resp, err := http.Get("/api/whoami"); err != nil { return nil, err } return parseUserJson(resp) }
Promisify allows JS to call the underlying function via reflection and automatically detects an 'error' return type, using the following rules, in order:
- If the function panics, the promise is rejected with the panic value.
- If the last return is of type 'error', then the promise is rejected if the returned error is non-nil.
- The promise is resolved with the remaining return values, according to how many there are: 0: resolved with nil 1: resolved with that value 2+: resolved with a slice of the values
If you want to manage the promise directly, use Promise:
func whoamiPromise() *js.Object { var p promise.Promise go func() { if user, err := whoami(); err == nil { p.Resolve(user) } else { p.Reject(err) } } return p.Js() }
Known Issues ¶
This package still has some rough edges:
- Does not adopt promise state when a promise is returned from a handler. E.g.: func Op1() Promise {...} func Op2() Promise {...} // Fails because when Op2 returns a promise, log is immediately called // instead of waiting for the Op2 promise to be fulfilled. Op1().Then(Op2, nil).Then(log, nil) To fix this, we need to be able to inspect the result of the success function and determine if it's a Promise (has a .then method), and if so we need to trigger downstream promises off of that instead of directly passing the result to the downstream promises.
- Does not do JS object type detection on .then() args. The promises spec suggests we should handle arbitrary arguments. E.g: somePromise.then(function(){...}, 123) should be equivalent to somePromise.then(function(){...})
- Promisify() doesn't not auto-convert JS to strongly-typed Go types. E.g.: type Foo string func something(f Foo) {...} cannot be called from JS as: something("asdf") Instead, something must have signature: func something(f string) { ... }
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Promisify ¶
func Promisify(fn interface{}) interface{}
Promisify takes any Go function and converts it to a function that runs asynchronously and returns a Promise.
Note: Currently this does not convert javascript types to Go types even if they are structurally equivalent. It therefore works only with plain data types or values explicitly created by Go code (passed back to java).
Types ¶
type Callback ¶
type Callback func(value interface{}) interface{}
Callbacks are provided to promises and called when the promise is fulfilled (with the fulfilled value) or rejected (with the error). The return of the callback is passed to dependencies.
type Promise ¶
type Promise struct {
// contains filtered or unexported fields
}
Promise represents most of an implementation of the JS Promise/A+ spec (https://promisesaplus.com/).
Typical usage is:
func ExportedToJavascript(arg1 string, arg2 int, ...) *Promise { var p Promise go func() { result, err := computeResult(arg1, arg2, ...) if err == nil { p.Resolve(result) } else { p.Reject(err) } }() return p.Js() }
This structure can be automatically implemented by Promisify(...), for example:
Promisify(computeResult)
func (*Promise) Js ¶
Js creates a JS wrapper object for this promise that includes the 'then' method required by the Promises/A+ spec.
func (*Promise) Reject ¶
func (p *Promise) Reject(err interface{}) interface{}
Reject this promise with the specified errror. Either Resolve or Reject may be called at most once on a promise instance.
func (*Promise) Resolve ¶
func (p *Promise) Resolve(value interface{}) interface{}
Resolve this promise with the provided value. Either Resolve or Reject may be called at most once on a promise instance.
func (*Promise) Then ¶
Then registers success and failure to be called if the promise is fulfilled or rejected respectively. It returns a new promise that will be resolved or rejected with the result of the success or failure callbacks.
Note that if success or failure return a promise, the promise itself is passed along as the value rather than adopting the returned promise's state.