npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

marko-async

v2.2.2

Published

Async taglib for Marko

Downloads

468

Readme

marko-async

The marko-async taglib provides support for 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, fragments of the template that depend on data from data providers are rendered asynchronously and wait only on the associated data provider to complete. The template rendering will only be delayed for data that the template actually needs.

Example

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);
}
<async-fragment data-provider="data.userProfileDataProvider"
    var="userProfile">

    <ul>
        <li>
            First name: ${userProfile.firstName}
        </li>
        <li>
            Last name: ${userProfile.lastName}
        </li>
        <li>
            Email address: ${userProfile.email}
        </li>
    </ul>

</async-fragment>

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 <async-fragment> tag:
<async-fragment data-provider="data.userProfileDataProvider"
    var="userProfile"
    client-reorder="true">

    <ul>
        <li>
            First name: ${userProfile.firstName}
        </li>
        <li>
            Last name: ${userProfile.lastName}
        </li>
        <li>
            Email address: ${userProfile.email}
        </li>
    </ul>

</async-fragment>
  1. Add the <async-fragments> to the end of the page.

If the client-reorder is true then a placeholder element will be rendered to the output instead of the final HTML for the async fragment. The async fragment will be instead rendered at the end of the page and client-side JavaScript code will be used to move the async fragment into the proper place in the DOM. The <async-fragments> will be where the out-of-order fragments are rendered before they are moved into place. If there are any out-of-order fragments 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

<async-fragment>

Supported Attributes:

  • arg (expression): The argument object to provide to the data provider function.
  • arg-<arg_name> (string): An argument to add to the arg object provided to the data provider function.
  • client-reorder (boolean): If true, then the async fragments will be flushed in the order they complete and JavaScript running on the client will be used to move the async fragments into the proper HTML order in the DOM. Defaults to false.
  • data-provider (expression, required): The source of data for the async fragment. Must be a reference to one of the following:
    • Function(callback)
    • Function(args, callback)
    • Promise
    • Data
  • error-message (string): Message to output if the fragment errors out. Specifying this will prevent the rendering from aborting.
  • name (string): Name to assign to this async fragment. Used for debugging purposes as well as by the show-after attribute (see below).
  • placeholder (string): Placeholder text to show while waiting for an out-of-order fragment to complete. Only applicable if client-reorder is set to true.
  • show-after (string): When client-reorder is set to true then displaying this fragment will be delayed until the referenced async fragment is shown.
  • timeout (integer): Override the default timeout of 10 seconds with this param. Units are in milliseconds so timeout="40000" would give a 40 second timeout.
  • timeout-message (string): Message to output if the fragment times out. Specifying this will prevent the rendering from aborting.
  • var: Variable name to use when consuming the data provided by the data provider

<async-fragment-placeholder>

This tag can be used to control what text is shown while an out-of-order async fragment is waiting to be loaded. Only applicable if client-reorder is set to true.

Example:

<async-fragment data-provider="data.userDataProvider" var="user" client-reorder>
    <async-fragment-placeholder>
        Loading user data...
    </async-fragment-placeholder>

    <ul>
        <li>First name: ${user.firstName}</li>
        <li>Last name: ${user.lastName}</li>
    </ul>

</async-fragment>

<async-fragment-error>

This tag can be used to control what text is shown when an async fragment errors out.

Example:

<async-fragment data-provider="data.userDataProvider" var="user">
    <async-fragment-error>
        An error occurred!
    </async-fragment-error>

    <ul>
        <li>First name: ${user.firstName}</li>
        <li>Last name: ${user.lastName}</li>
    </ul>
</async-fragment>

<async-fragment-timeout>

This tag can be used to control what text is shown when an async fragment times out.

Example:

<async-fragment data-provider="data.userDataProvider" var="user">
    <async-fragment-timeout>
    A timeout occurred!
    </async-fragment-timeout>

    <ul>
        <li>First name: ${user.firstName}</li>
        <li>Last name: ${user.lastName}</li>
    </ul>
</async-fragment>

<async-fragments>

Container for all out-of-order async fragments. If any <async-fragment> 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:

<!DOCTYPE html>
<html>
...
<body>
    ...
    <async-fragment ... client-reorder/>
    ...
    <async-fragments/>
</body>
</html>