Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Promises

A promise stands for a value that may not be available yet, such as a document that is still loading. It starts pending and later resolves to a value.

Promises usually come from the host or from the engine: texl.import returns one, and so does a JavaScript async function passed to a template. You can also create them yourself with the promise namespace.

Swan promises are simple:

  • A promise resolves at most once. Later attempts are ignored.
  • A promise never fails. If it resolves to an Undefined value, it holds Nothing instead.

Using a value that arrives later

Swan code cannot stop and wait. Instead, you give the promise a function to apply to its value. p ~> f returns a new promise, which resolves to f applied to the value of p:

p = promise.create()
q = p ~> (x -> x * 2)
promise.resolve p 21
q                    # => Promise(42)

If p is already resolved, f runs immediately. Otherwise it runs when p resolves. Several functions can wait on the same promise.

To chain several steps, write them one after the other. ~> is left-associative, so p ~> f ~> g means (p ~> f) ~> g: g is applied to the result of f:

p = promise.create()
q = p ~> (x -> x + 1) ~> (x -> x * 10)
promise.resolve p 1
q                    # => Promise(20)

A value that is not a promise is treated as an already resolved promise:

3 ~> (x -> x + 1)    # => Promise(4)

A tuple of promises gives a tuple of new promises, and a tuple of functions gives one new promise per function.

Keeping the result

The function you pass to ~> runs later, possibly after the rest of the expression. To make its result available to later code, bind it globally with bind:

p = promise.create()
p ~> (v -> bind "result" v)
promise.resolve p "done"
result               # => "done"

Promises in templates

When a tag of a template returns a promise, rendering waits until the promise resolves and writes its value. This is how a template uses an imported document:

<% texl.import("header.texl") ~> (doc -> doc.rendering) %>

The next tags run only after the promise resolves, so they can use what the callback bound. See Waiting for values.

Truth value

As a condition, a promise is false while it is pending and true once it is resolved, whatever its value. So p ? x tests whether p has resolved, not its value. To test the value, use it inside ~>:

p = promise.create ()
p ? "resolved" ; "pending"        # => "pending"
q = p ~> (v -> v ? "yes" ; "no")
promise.resolve p FALSE
p ? "resolved" ; "pending"        # => "resolved"
q                                 # => Promise("no")