Async Taglib // MarkoImprove this page
Note: This functionality used to be provided by the
<async-fragment>
tag which has been deprecated in favor of<await>
.
Example
Pass a promise (or callback) to the template:
var template = ;var request = ;moduleexports = template;
And await the data:
Name: ${user.firstName} ${user.lastName}Email address: ${user.email}
Philosophy
Marko includes a taglib that supports the more efficient and simpler "Pull Model "approach to providing templates with view model data.
- Push Model: Request all needed data upfront and wait for all of the data to be received before building the view model and then rendering the template.
- Pull Model: Pass asynchronous data provider functions to template immediately start rendering the template. Let the template pull the data needed during rendering.
The Pull Model approach to template rendering requires the use of a templating engine that supports asynchronous template rendering (e.g. marko and dust). This is because before rendering the template begins not all of data may have been fully retrieved. Parts of a template that depend on data that is not yet available are rendered asynchronously with the Pull Model approach.
Push Model versus Pull Model
The problem with the traditional Push Model approach is that template rendering is delayed until all data has been fully received. This reduces the time to first byte, and it also may result in the server sitting idle while waiting for data to be loaded from remote services. In addition, if certain data is no longer needed by a template then only the template needs to be modified and not the controller.
With the new Pull Model approach, template rendering begins immediately. In addition, sections of the template that depend on data from data providers are rendered asynchronously and await
only the associated data provider's completion. The template rendering will only be delayed for data that the template actually needs.
Out-of-order Flushing
The marko-async taglib also supports out-of-order flushing. Enabling out-of-order flushing requires two steps:
Add the
client-reorder
attribute to the<await>
tag:Name: ${user.firstName} ${user.lastName}Email address: ${user.email}Add the
<await-reorderer>
to the end of the page.......
If client-reorder
is true
then a placeholder element will be rendered to the output instead of the final HTML for the await instance. The instance will be instead rendered at the end of the page and client-side JavaScript code will be used to move the await's contents into the proper place in the DOM. The <await-reorderer>
will be where the out-of-order instances are rendered before they are moved into place. If there are any out-of-order instances then inline JavaScript code will be injected into the page at this location to move the DOM nodes into the proper place in the DOM.
Events
You may listen to these events on the AsyncStream returned from a template's render
method or the wrapped stream if it is an event emitter (like node's http res
stream).
await:begin
- emits an object with the keysname
,dataProvider
, andclientReorder
when the<await>
tag begins awaiting its promise/callback.await:beforeRender
- emits the same object with the keyout
(the async output stream) added once the promise/callback has returned and the<await>
tag is about to render its contents.await:error
- emits the same object with the keyerror
(theError
) added, if an error occursawait:timeout
- emits the same object with the keytimedout
(a boolean set totrue
) added, if a timeout occursawait:finish
- emits the same the keyfinished
(a boolean set totrue
) added once the<await>
tag finishes
Taglib API
<await>
Required Argument:
<awaitvarName from dataprovider>
var
: Variable name to use when consuming the data provided by the data providerdata provider
: The source of data to await. Must be a reference to one of the following:Function(callback)
Function(args, callback)
Promise
- Data
Supported Attributes:
arg
(expression): The argument object to provide to the data provider function.arg-<arg_name>
(string): An argument to add to thearg
object provided to the data provider function.client-reorder
(boolean): Iftrue
, then the await instances will be flushed in the order they complete and JavaScript running on the client will be used to move the await instances into the proper HTML order in the DOM. Defaults tofalse
.error-message
(string): Message to output if the data provider errors out. Specifying this will prevent the rendering from aborting.name
(string): Name to assign to this await instance. Used for debugging purposes as well as by theshow-after
attribute (see below).placeholder
(string): Placeholder text to show while waiting for a data provider to complete. Only applicable ifclient-reorder
is set totrue
.show-after
(string): Whenclient-reorder
is set totrue
then displaying this instance's content will be delayed until the referenced await instance is shown.timeout
(integer): Override the default timeout of 10 seconds with this param. Units are inmilliseconds sotimeout=40000
would give a 40 second timeout.timeout-message
(string): Message to output if the data provider times out. Specifying this will prevent the rendering from aborting.
<await-placeholder>
This tag can be used to control what text is shown while an out-of-order await instance is waiting to be loaded. Only applicable if client-reorder
is set to true
.
Example:
Loading user data...First name: ${user.firstName}Last name: ${user.lastName}
<await-error>
This tag can be used to control what text is shown when a data provider errors out.
Example:
An error occurred!First name: ${user.firstName}Last name: ${user.lastName}
<await-timeout>
This tag can be used to control what text is shown when a data provider times out.
Example:
A timeout occurred!First name: ${user.firstName}Last name: ${user.lastName}
<await-reorderer>
Container for all out-of-order await instances. If any <await>
tags have client-reorder
set to true then this tag needs to be included in the page template (typically, right before the closing </body>
tag).
Example:
......