async({...})
, with an expression written in its argument, allows
that expression to be evaluated in an asynchronous, or non-blocking
manner. async
returns an object with class c("async", "promise")
which
implements the promise interface.
An expression, to be executed asynchronously.
Undocumented.
Rewrite chained calls that use await
(see
below)
Compilation level; same options as for gen.
Set TRUE to enter the browser immediately on executing the first R expression.
Set TRUE to single-step at implementation level, immediately upon execution.
Enable verbose logging by passing a function to
trace
, like trace=cat
. This function should take a character
argument.
A promise, or something that can be converted to such
by promises::as.promise()
.
This argument will be forced if the promise rejects. If it is a function, it will be called with the error condition.
async()
returns an object with class "promise," as
defined by the promises package (i.e., rather than the kind of
promise used in R's lazy evaluation.)
In the context of an async
or stream
, await(x)
returns
the resolved value of a promise x
, or stops with an error.
An example Shiny app using async/await
is on Github:
https://github.com/crowding/cranwhales-await
When an async
object is activated, it will evaluate its expression
until it reaches the keyword await
. The async
object will return
to its caller and preserve the partial state of its evaluation.
When the awaited promise is resolved, evaluation continues from where
the async
left off.
When an async block finishes (either by reaching the end, or using
return()
), the promise resolves with the resulting value. If the
async block stops with an error, the promise is rejected with
that error.
Async blocks and generators are conceptually related and share much of the same underlying mechanism. You can think of one as "output" and the other as "input". A generator pauses until a value is requested, runs until it has a value to output, then pauses again. An async runs until it requires an external value, pauses until it receives the value, then continues.
The syntax rules for an async
are analogous to those for gen()
;
await
must appear only within the arguments of functions for
which there is a pausable implementation (See [pausables()]
). For
async
the default split_pipes=TRUE
is enabled; this will
rearrange some expressions to satisfy this requirement.
When split_pipes=FALSE
, await()
can only appear in the
arguments of pausables and not ordinary R functions. This is an
inconvenience as it prevents using await()
in a pipeline. With
split_pipes=TRUE
applies some syntactic sugar: if an await()
appears in the leftmost, unnamed, argument of an R function, the
pipe will be "split" at that call using a temporary variable. For
instance, either
async(makeRequest() |> await() |> sort())
or, equivalently,
async(sort(await(makeRequest())))
will be effectively rewritten to something like
async({.tmp <- await(makeRequest()); sort(.tmp)})
This works only so long as await
appears in calls that evaluate
their leftmost arguments normally. split_pipes
can backfire if
the outer call has other side effects; for instance
suppressWarnings(await(x))
will be rewritten as {.tmp <- await(x); suppressWarnings(x)}
, which would defeat the purpose.
If async
is given a function expression, like async(function(...) ...)
, it will return an "async function" i.e. a function that
constructs an async.