Async Taglib
=====================
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](https://github.com/marko-js/marko) and [dust](https://github.com/linkedin/dustjs)). 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.
# Example
```javascript
var template = require('./template.marko');
module.exports = function(req, res) {
var userId = req.query.userId;
template.render({
userProfileDataProvider: function(callback) {
userProfileService.getUserProfile(userId, callback);
}
}, res);
}
```
```html
-
First name: ${userProfile.firstName}
-
Last name: ${userProfile.lastName}
-
Email address: ${userProfile.email}
```
# Out-of-order Flushing
The marko-async taglib also supports out-of-order flushing. Enabling out-of-order flushing requires two steps:
1. Add the `client-reorder` attribute to the `` tag:
```html
-
First name: ${userProfile.firstName}
-
Last name: ${userProfile.lastName}
-
Email address: ${userProfile.email}
```
2. Add the `` 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 `` 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.
# Taglib API
## ``
**Required Argument:**
```js
```
* __`var`__: Variable name to use when consuming the data provided by the data provider
* __`data 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-`__ (string): An argument to add to the `arg` object provided to the data provider function.
* __`client-reorder`__ (boolean): If `true`, 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 to `false`.
* __`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 the `show-after` attribute (see below).
* __`placeholder`__ (string): Placeholder text to show while waiting for a data provider to complete. Only applicable if `client-reorder` is set to `true`.
* __`show-after`__ (string): When `client-reorder` is set to `true` 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 so `timeout="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.
## ``
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:
```html
Loading user data...
- First name: ${user.firstName}
- Last name: ${user.lastName}
```
## ``
This tag can be used to control what text is shown when a data provider errors out.
Example:
```html
An error occurred!
- First name: ${user.firstName}
- Last name: ${user.lastName}
```
## ``
This tag can be used to control what text is shown when a data provider times out.
Example:
```html
A timeout occurred!
- First name: ${user.firstName}
- Last name: ${user.lastName}
```
## ``
Container for all out-of-order await instances. If any `` tags have `client-reorder` set to true then this tag needs to be included in the page template (typically, right before the closing `
...