Files
liquidjs/tutorials/sync-and-async.html
T

216 lines
27 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head prefix="og: https://ogp.me/ns#">
<meta charset="utf-8">
<title>Sync and Async | LiquidJS</title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="LiquidJS is a simple, expressive and safe Shopify / GitHub Pages compatible template engine in pure JavaScript.">
<link rel="dns-prefetch" href="https://cdn.jsdelivr.net/">
<link rel="manifest" href="/manifest.json">
<!-- Canonical links -->
<link rel="canonical" href="https://liquidjs.com/tutorials/sync-and-async.html">
<!-- Alternative links -->
<link rel="alternative" hreflang="en" href="https://liquidjs.com/tutorials/sync-and-async">
<link rel="alternative" hreflang="zh-cn" href="https://liquidjs.com/zh-cn/tutorials/sync-and-async">
<!-- Icon -->
<link rel="apple-touch-icon" sizes="57x57" href="../icon/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="114x114" href="../icon/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="72x72" href="../icon/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="144x144" href="../icon/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="60x60" href="../icon/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="120x120" href="../icon/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="76x76" href="../icon/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="152x152" href="../icon/apple-touch-icon-152x152.png">
<link rel="icon" type="image/png" href="../icon/favicon-196x196.png" sizes="196x196">
<link rel="icon" type="image/png" href="../icon/favicon-160x160.png" sizes="160x160">
<link rel="icon" type="image/png" href="../icon/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="../icon/favicon-16x16.png" sizes="16x16">
<link rel="icon" type="image/png" href="../icon/favicon-32x32.png" sizes="32x32">
<meta name="msapplication-TileColor" content="#2f83cd">
<meta name="msapplication-TileImage" content="../icon/mstile-144x144.png">
<link rel="stylesheet" href="../css/navy.css">
<link rel="alternate" href="../atom.xml" title="LiquidJS" type="application/atom+xml">
<meta name="generator" content="Hexo 7.3.0"></head>
<body>
<div id="container">
<header id="header" class="wrapper">
<div id="header-inner" class="inner">
<h1 id="logo-wrap">
<a href="../index.html" id="logo">LiquidJS</a>
</h1>
<nav id="main-nav">
<a href="../tutorials/intro-to-liquid.html" class="main-nav-link">Tutorials</a><a href="../tags/overview.html" class="main-nav-link">Tags</a><a href="../filters/overview.html" class="main-nav-link">Filters</a><a href="../playground.html" class="main-nav-link">Playground</a><a href="../api/classes/Liquid.html" class="main-nav-link">API</a>
<div id="search-input-wrap">
<i id="search-input-icon" class="icon-search"></i>
<input type="search" id="search-input" placeholder="Search...">
</div>
</nav>
<div class="main-nav-link icon-nav-link">
<label><i class="icon-network"></i> <span class="icon-nav-title">English</span></label>
<select id="lang-select" data-canonical="tutorials/sync-and-async.html">
<option value="en" selected>English</option>
<option value="zh-cn">简体中文</option>
</select>
</div>
<a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs" class="main-nav-link icon-nav-link"><i class="icon-github"></i> <span class="icon-nav-title">GitHub</span></a>
<a id="mobile-nav-toggle">
<span class="mobile-nav-toggle-bar"></span>
<span class="mobile-nav-toggle-bar"></span>
<span class="mobile-nav-toggle-bar"></span>
</a>
</div>
</header>
<div id="content-wrap">
<div id="content" class="wrapper">
<div id="content-inner">
<aside id="sidebar" role="navigation">
<div class="inner">
<strong class="sidebar-title">Getting Started</strong><a href="intro-to-liquid.html" class="sidebar-link">Intro to Liquid</a><a href="setup.html" class="sidebar-link">Setup</a><a href="options.html" class="sidebar-link">Options</a><a href="render-file.html" class="sidebar-link">Render Files</a><a href="partials-and-layouts.html" class="sidebar-link">Includes and Layouts</a><a href="use-in-expressjs.html" class="sidebar-link">Use in Express.js</a><strong class="sidebar-title">Advanced</strong><a href="caching.html" class="sidebar-link">Caching</a><a href="escaping.html" class="sidebar-link">Escaping</a><a href="register-filters-tags.html" class="sidebar-link">Register Filters/Tags</a><a href="access-scope-in-filters.html" class="sidebar-link">Access Scope in Filters</a><a href="parse-parameters.html" class="sidebar-link">Parse Parameters</a><a href="render-tag-content.html" class="sidebar-link">Render Tag Content</a><a href="drops.html" class="sidebar-link">Liquid Drops</a><a href="sync-and-async.html" class="sidebar-link current">Sync and Async</a><a href="whitespace-control.html" class="sidebar-link">Whitespace Control</a><a href="plugins.html" class="sidebar-link">Plugins</a><a href="operators.html" class="sidebar-link">Operators</a><a href="truthy-and-falsy.html" class="sidebar-link">Truthy and Falsy</a><a href="dos.html" class="sidebar-link">DoS</a><strong class="sidebar-title">Miscellaneous</strong><a href="migrate-to-9.html" class="sidebar-link">Migrate to LiquidJS 9</a><a href="changelog.html" class="sidebar-link">Changelog</a><a href="differences.html" class="sidebar-link">Differences with Shopify/liquid</a><a href="contribution-guidelines.html" class="sidebar-link">Contribution Guidelines</a>
</div>
</aside>
<article class="article-container" itemscope itemtype="https://schema.org/Article">
<div class="article-inner">
<div class="article">
<div class="inner">
<header class="article-header">
<h1 class="article-title" itemprop="name">Sync and Async</h1>
<a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/edit/master/docs/source/tutorials/sync-and-async.md" class="article-edit-link" title="Improve this doc"><i class="icon-pencil"></i></a>
</header>
<div class="article-content" itemprop="articleBody">
<p>LiquidJS supports both sync and async evaluate, and can be used with Promises. To reuse the same set of tag/filter implementations in both sync and async, LiquidJS tags are implemented as generators.</p>
<h2 id="Sync-and-Async-API" class="article-heading"><a href="#Sync-and-Async-API" class="headerlink" title="Sync and Async API"></a>Sync and Async API<a class="article-anchor" href="#Sync-and-Async-API" aria-hidden="true"></a></h2><p>All major methods on <a href="/api/classes/Liquid.html">Liquid</a> supports both sync and async. These methods return Promises:</p>
<ul>
<li><code>render()</code></li>
<li><code>renderFile()</code></li>
<li><code>parseFile()</code></li>
<li><code>parseAndRender()</code></li>
<li><code>evalValue()</code></li>
</ul>
<p>The synchronous version of methods contains a <code>Sync</code> suffix:</p>
<ul>
<li><code>renderSync()</code></li>
<li><code>renderFileSync()</code></li>
<li><code>parseFileSync()</code></li>
<li><code>parseAndRenderSync()</code></li>
<li><code>evalValueSync()</code></li>
</ul>
<h2 id="Implement-Sync-Compatible-Tags" class="article-heading"><a href="#Implement-Sync-Compatible-Tags" class="headerlink" title="Implement Sync-Compatible Tags"></a>Implement Sync-Compatible Tags<a class="article-anchor" href="#Implement-Sync-Compatible-Tags" aria-hidden="true"></a></h2><p>LiquidJS uses a generator-based async implementation to support both async and sync in one piece of tag implementation. For example, below <code>UpperTag</code> can be used in both <code>engine.renderSync()</code> and <code>engine.render()</code>.</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">TagToken</span>, <span class="title class_">Context</span>, <span class="title class_">Emitter</span>, <span class="title class_">TopLevelToken</span>, <span class="title class_">Value</span>, <span class="title class_">Tag</span>, <span class="title class_">Liquid</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;liquidjs&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Usage: &#123;% upper &quot;alice&quot; %&#125;</span></span><br><span class="line"><span class="comment">// Output: ALICE</span></span><br><span class="line">engine.<span class="title function_">registerTag</span>(<span class="string">&#x27;upper&#x27;</span>, <span class="keyword">class</span> <span class="title class_">UpperTag</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Tag</span> &#123;</span><br><span class="line"> <span class="keyword">private</span> <span class="attr">value</span>: <span class="title class_">Value</span></span><br><span class="line"> <span class="title function_">constructor</span> (<span class="params"><span class="attr">token</span>: <span class="title class_">TagToken</span>, <span class="attr">remainTokens</span>: <span class="title class_">TopLevelToken</span>[], <span class="attr">liquid</span>: <span class="title class_">Liquid</span></span>) &#123;</span><br><span class="line"> <span class="variable language_">super</span>(token, remainTokens, liquid)</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">value</span> = <span class="keyword">new</span> <span class="title class_">Value</span>(token.<span class="property">args</span>, liquid)</span><br><span class="line"> &#125;</span><br><span class="line"> * <span class="title function_">render</span> (<span class="attr">ctx</span>: <span class="title class_">Context</span>, <span class="attr">emitter</span>: <span class="title class_">Emitter</span>) &#123;</span><br><span class="line"> <span class="keyword">const</span> title = <span class="keyword">yield</span> <span class="variable language_">this</span>.<span class="property">value</span>.<span class="title function_">value</span>(ctx)</span><br><span class="line"> emitter.<span class="title function_">write</span>(title.<span class="title function_">toUpperCase</span>())</span><br><span class="line"> &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p>All builtin tags are implemented this way and safe to use in both sync and async (Ill call it <em>sync-compatible</em>). To make your custom tag <em>sync-compatible</em>, youll need to:</p>
<ul>
<li>declare render function as <code>* render()</code>, in which</li>
<li>do not directly <code>return &lt;Promise&gt;</code>, and</li>
<li>do not call any APIs that returns a Promise.</li>
</ul>
<h2 id="Call-APIs-that-return-a-Promise" class="article-heading"><a href="#Call-APIs-that-return-a-Promise" class="headerlink" title="Call APIs that return a Promise"></a>Call APIs that return a Promise<a class="article-anchor" href="#Call-APIs-that-return-a-Promise" aria-hidden="true"></a></h2><p>But LiquidJS is Promise-friendly, right? You can still call Promise-based functions and wait for that Promise within tag implementations. Just replace <code>await</code> with <code>yield</code>. e.g. were calling <code>fs.readFile()</code> which returns a <code>Promise</code>:</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">* <span class="title function_">render</span> (<span class="attr">ctx</span>: <span class="title class_">Context</span>, <span class="attr">emitter</span>: <span class="title class_">Emitter</span>) &#123;</span><br><span class="line"> <span class="keyword">const</span> file = <span class="keyword">yield</span> <span class="variable language_">this</span>.<span class="property">value</span>.<span class="title function_">value</span>(ctx)</span><br><span class="line"> <span class="keyword">const</span> title = <span class="keyword">yield</span> fs.<span class="title function_">readFile</span>(file, <span class="string">&#x27;utf8&#x27;</span>)</span><br><span class="line"> emitter.<span class="title function_">write</span>(title.<span class="title function_">toUpperCase</span>())</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Now that this <code>* render()</code> calls an API that returns a Promise, so its no longer <em>sync-compatible</em>.</p>
<blockquote class="note info"><strong class="note-title">Non Sync-Compatible Tags</strong><p>Non <em>sync-compatible</em> tags are also valid tags, will work just fine for asynchronous API calls. When called synchronously, tags that return a <code>Promise</code> will be rendered as <code>[object Promise]</code>.</p>
</blockquote>
<h2 id="Convert-LiquidJS-async-Generator-to-Promise" class="article-heading"><a href="#Convert-LiquidJS-async-Generator-to-Promise" class="headerlink" title="Convert LiquidJS async Generator to Promise"></a>Convert LiquidJS async Generator to Promise<a class="article-anchor" href="#Convert-LiquidJS-async-Generator-to-Promise" aria-hidden="true"></a></h2><p>You can convert a Generator to Promise by <a href="/api/functions/toPromise.html">toPromise</a>, for example:</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">TagToken</span>, <span class="title class_">Context</span>, <span class="title class_">Emitter</span>, <span class="title class_">TopLevelToken</span>, <span class="title class_">Value</span>, <span class="title class_">Tag</span>, <span class="title class_">Liquid</span>, toPromise &#125; <span class="keyword">from</span> <span class="string">&#x27;liquidjs&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Usage: &#123;% upper &quot;alice&quot; %&#125;</span></span><br><span class="line"><span class="comment">// Output: ALICE</span></span><br><span class="line">engine.<span class="title function_">registerTag</span>(<span class="string">&#x27;upper&#x27;</span>, <span class="keyword">class</span> <span class="title class_">UpperTag</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Tag</span> &#123;</span><br><span class="line"> <span class="keyword">private</span> <span class="attr">value</span>: <span class="title class_">Value</span></span><br><span class="line"> <span class="title function_">constructor</span> (<span class="params"><span class="attr">token</span>: <span class="title class_">TagToken</span>, <span class="attr">remainTokens</span>: <span class="title class_">TopLevelToken</span>[], <span class="attr">liquid</span>: <span class="title class_">Liquid</span></span>) &#123;</span><br><span class="line"> <span class="variable language_">super</span>(token, remainTokens, liquid)</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">value</span> = <span class="keyword">new</span> <span class="title class_">Value</span>(token.<span class="property">args</span>, liquid)</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">async</span> <span class="title function_">render</span> (<span class="attr">ctx</span>: <span class="title class_">Context</span>, <span class="attr">emitter</span>: <span class="title class_">Emitter</span>) &#123;</span><br><span class="line"> <span class="keyword">const</span> title = <span class="keyword">await</span> <span class="title function_">toPromise</span>(<span class="variable language_">this</span>.<span class="property">value</span>.<span class="title function_">value</span>(ctx))</span><br><span class="line"> emitter.<span class="title function_">write</span>(title.<span class="title function_">toUpperCase</span>())</span><br><span class="line"> &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<h2 id="Async-only-Tags" class="article-heading"><a href="#Async-only-Tags" class="headerlink" title="Async only Tags"></a>Async only Tags<a class="article-anchor" href="#Async-only-Tags" aria-hidden="true"></a></h2><p>If your tag is intend to be used only asynchronously, it can be declared as <code>async render()</code> so you can use <code>await</code> in its implementation directly:</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; toPromise, <span class="title class_">TagToken</span>, <span class="title class_">Context</span>, <span class="title class_">Emitter</span>, <span class="title class_">TopLevelToken</span>, <span class="title class_">Value</span>, <span class="title class_">Tag</span>, <span class="title class_">Liquid</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;liquidjs&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Usage: &#123;% upper &quot;alice&quot; %&#125;</span></span><br><span class="line"><span class="comment">// Output: ALICE</span></span><br><span class="line">engine.<span class="title function_">registerTag</span>(<span class="string">&#x27;upper&#x27;</span>, <span class="keyword">class</span> <span class="title class_">UpperTag</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Tag</span> &#123;</span><br><span class="line"> <span class="keyword">private</span> <span class="attr">value</span>: <span class="title class_">Value</span></span><br><span class="line"> <span class="title function_">constructor</span> (<span class="params"><span class="attr">token</span>: <span class="title class_">TagToken</span>, <span class="attr">remainTokens</span>: <span class="title class_">TopLevelToken</span>[], <span class="attr">liquid</span>: <span class="title class_">Liquid</span></span>) &#123;</span><br><span class="line"> <span class="variable language_">super</span>(token, remainTokens, liquid)</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">value</span> = <span class="keyword">new</span> <span class="title class_">Value</span>(token.<span class="property">args</span>, liquid)</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">async</span> <span class="title function_">render</span> (<span class="attr">ctx</span>: <span class="title class_">Context</span>, <span class="attr">emitter</span>: <span class="title class_">Emitter</span>) &#123;</span><br><span class="line"> <span class="keyword">const</span> title = <span class="keyword">await</span> <span class="title function_">toPromise</span>(<span class="variable language_">this</span>.<span class="property">value</span>.<span class="title function_">value</span>(ctx))</span><br><span class="line"> emitter.<span class="title function_">write</span>(<span class="string">`&lt;h1&gt;<span class="subst">$&#123;title&#125;</span>&lt;/h1&gt;`</span>)</span><br><span class="line"> &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2024-08-16T16:55:41.721Z" itemprop="dateModified">Last updated: 2024-08-16</time>
<a href="drops.html" class="article-footer-prev" title="Liquid Drops"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="whitespace-control.html" class="article-footer-next" title="Whitespace Control"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
</div>
<aside id="article-toc" role="navigation">
<div id="article-toc-inner">
<div id="article-toc-inner-list">
<strong class="sidebar-title">Contents</strong>
<ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#Sync-and-Async-API"><span class="toc-text">Sync and Async API</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Implement-Sync-Compatible-Tags"><span class="toc-text">Implement Sync-Compatible Tags</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Call-APIs-that-return-a-Promise"><span class="toc-text">Call APIs that return a Promise</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Convert-LiquidJS-async-Generator-to-Promise"><span class="toc-text">Convert LiquidJS async Generator to Promise</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Async-only-Tags"><span class="toc-text">Async only Tags</span></a></li></ol>
</div>
<a href="#" id="article-toc-top">Back to Top</a>
</div>
</aside>
</div>
</article>
</div>
</div>
</div>
<footer id="footer" class="wrapper">
<div class="inner">
<div id="footer-copyright">
&copy; 2024 <a href="https://github.com/harttle/liquidjs/graphs/contributors" rel="external nofollow noreferrer" target="_blank">Harttle</a><br>
Documentation licensed under <a href="https://creativecommons.org/licenses/by/4.0/" rel="external nofollow noreferrer" target="_blank">CC BY 4.0</a>.
</div>
<div id="footer-links">
<a href="https://twitter.com/harttleharttle" rel="external nofollow noreferrer" class="footer-link" target="_blank"><i class="icon-twitter"></i></a>
<a href="https://opencollective.com/liquidjs" rel="external nofollow noreferrer" class="footer-link" target="_blank"><i class="icon-opencollective"></i></a>
<a href="https://github.com/harttle/liquidjs" rel="external nofollow noreferrer" class="footer-link" target="_blank"><i class="icon-github"></i></a>
</div>
</div>
</footer>
</div>
<div id="mobile-nav-dimmer"></div>
<nav id="mobile-nav">
<div id="mobile-nav-inner">
<ul id="mobile-nav-list">
<a href="../tutorials/intro-to-liquid.html" class="mobile-nav-link">Tutorials</a><a href="../tags/overview.html" class="mobile-nav-link">Tags</a><a href="../filters/overview.html" class="mobile-nav-link">Filters</a><a href="../playground.html" class="mobile-nav-link">Playground</a><a href="../api/classes/Liquid.html" class="mobile-nav-link">API</a>
</ul>
<div class="mobile-sidebar-list">
<strong class="mobile-nav-title">Getting Started</strong><a href="intro-to-liquid.html" class="mobile-nav-link">Intro to Liquid</a><a href="setup.html" class="mobile-nav-link">Setup</a><a href="options.html" class="mobile-nav-link">Options</a><a href="render-file.html" class="mobile-nav-link">Render Files</a><a href="partials-and-layouts.html" class="mobile-nav-link">Includes and Layouts</a><a href="use-in-expressjs.html" class="mobile-nav-link">Use in Express.js</a><strong class="mobile-nav-title">Advanced</strong><a href="caching.html" class="mobile-nav-link">Caching</a><a href="escaping.html" class="mobile-nav-link">Escaping</a><a href="register-filters-tags.html" class="mobile-nav-link">Register Filters/Tags</a><a href="access-scope-in-filters.html" class="mobile-nav-link">Access Scope in Filters</a><a href="parse-parameters.html" class="mobile-nav-link">Parse Parameters</a><a href="render-tag-content.html" class="mobile-nav-link">Render Tag Content</a><a href="drops.html" class="mobile-nav-link">Liquid Drops</a><a href="sync-and-async.html" class="mobile-nav-link current">Sync and Async</a><a href="whitespace-control.html" class="mobile-nav-link">Whitespace Control</a><a href="plugins.html" class="mobile-nav-link">Plugins</a><a href="operators.html" class="mobile-nav-link">Operators</a><a href="truthy-and-falsy.html" class="mobile-nav-link">Truthy and Falsy</a><a href="dos.html" class="mobile-nav-link">DoS</a><strong class="mobile-nav-title">Miscellaneous</strong><a href="migrate-to-9.html" class="mobile-nav-link">Migrate to LiquidJS 9</a><a href="changelog.html" class="mobile-nav-link">Changelog</a><a href="differences.html" class="mobile-nav-link">Differences with Shopify/liquid</a><a href="contribution-guidelines.html" class="mobile-nav-link">Contribution Guidelines</a>
</div>
</div>
<div id="mobile-button-list">
<a href="https://github.com/harttle/liquidjs" class="mobile-nav-link" rel="external" target="_blank"><i class="icon-github"></i></a>
<a href="https://opencollective.com/liquidjs" class="mobile-nav-link" rel="external" target="_blank"><i class="icon-opencollective"></i></a>
<div id="mobile-lang-select-wrap" class="mobile-nav-link">
<label for="mobile-lang-select"><i class="icon-network"></i></label>
<select id="mobile-lang-select" data-canonical="tutorials/sync-and-async.html">
<option value="en" selected>English</option>
<option value="zh-cn">简体中文</option>
</select>
</div>
</div>
</nav>
<script src="../js/main.js"></script>
<script src="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js"></script>
<script>
document.getElementById('search-input-wrap').classList.add('on');
docsearch({
apiKey: '01f36cc168657a26a385308b9e721bc6',
indexName: 'liquidjs',
inputSelector: '#search-input',
debug: false
});
</script>
</body>
</html>