UNPKG

enque

Version:

Run asynchonous functions in succession while potentially operating on the same data.

744 lines (509 loc) 30.7 kB
<!DOCTYPE html> <html> <head> <title>enQue.js</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <ul class="sections"> <li id="title"> <div class="annotation"> <h1>enQue.js</h1> </div> </li> <li id="section-1"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-1">&#182;</a> </div> <p>enQue class Author leathan License MIT</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-meta">'use strict'</span></pre></div></div> </li> <li id="section-2"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-2">&#182;</a> </div> <p><strong>Constructor</strong> Creates a new enQue object with the specified functions. <code>que = new enQue([fn1, fn2, fn3])</code> You can also create an empty object via <code>new enQue()</code></p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">enQue</span>(<span class="hljs-params">init</span>) </span>{ <span class="hljs-keyword">this</span>.que = []; <span class="hljs-keyword">if</span>(init) <span class="hljs-keyword">this</span>.add(init);</pre></div></div> </li> <li id="section-3"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-3">&#182;</a> </div> <p><strong>returns itself for use in chaining</strong></p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>; }</pre></div></div> </li> <li id="section-4"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p><strong>Compact</strong> Removes undefined and null values. This method should never ever be called directly, and it will probably become private in the future.. but who knows. <code>que.compact()</code></p> </div> <div class="content"><div class='highlight'><pre>enQue.prototype.compact = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; <span class="hljs-keyword">const</span> res = []; <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> val <span class="hljs-keyword">of</span> <span class="hljs-keyword">this</span>.que) <span class="hljs-keyword">if</span>(val) res[i++] = val; <span class="hljs-keyword">this</span>.que = res;</pre></div></div> </li> <li id="section-5"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p><strong>returns itself for use in chaining</strong></p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>; }</pre></div></div> </li> <li id="section-6"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p><strong>enQue.fill</strong> Fills an enQue object with <code>fn</code>‘s <code>n</code> times. <code>que.fill((_,n)=&gt;{console.log(&#39;works&#39;);n()}, 7)</code> running that que will display ‘works’ 7 times.</p> </div> <div class="content"><div class='highlight'><pre>enQue.prototype.fill = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">fn, n</span>) </span>{ <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; n; i++) { <span class="hljs-keyword">this</span>.que.push(fn); }</pre></div></div> </li> <li id="section-7"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-7">&#182;</a> </div> <p><strong>returns itself for use in chaining</strong></p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>; }</pre></div></div> </li> <li id="section-8"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-8">&#182;</a> </div> <p><strong>enQue.add</strong> Adds <code>fn</code> to the enQue object. <code>que.add((_,n,__,i)=&gt;{console.log(i)})</code> or you can specify an array of functions <code>que.add([fn1, fn1])</code></p> </div> <div class="content"><div class='highlight'><pre>enQue.prototype.add = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">fn</span>) </span>{ <span class="hljs-keyword">if</span>(fn.constructor.name === <span class="hljs-string">'Array'</span>) { <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>, l = fn.length; i &lt; l; i++) { <span class="hljs-keyword">this</span>.que.push(fn[i]); } } <span class="hljs-keyword">else</span> { <span class="hljs-keyword">this</span>.que.push(fn); }</pre></div></div> </li> <li id="section-9"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-9">&#182;</a> </div> <p><strong>returns itself for use in chaining</strong></p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>; }</pre></div></div> </li> <li id="section-10"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p><strong>enQue.clear</strong> Clears all functions from the que <code>que.clear()</code></p> </div> <div class="content"><div class='highlight'><pre>enQue.prototype.clear = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">this</span>.que = []; <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;</pre></div></div> </li> <li id="section-11"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p><strong>returns itself for use in chaining</strong></p> </div> <div class="content"><div class='highlight'><pre>}</pre></div></div> </li> <li id="section-12"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p><strong>enQue.remove</strong> Removes an item from the que. <code>que.remove(&quot;(_,n,__,i)=&gt;{console.log(i)}&quot;)</code> <code>que.remove(fn1, 2)</code> removes 2 occurances of fn1 <code>que.remove(7)</code> removes the 8th function (0 indexed) to remove an array of function refs and/or strinfified functions. <code>que.remove([fn1, &quot;(_,n,__,i)=&gt;{console.log(i)}&quot;, fn2])</code> <code>que.remove([fn1, fn2, fn3], 2)</code> will only remove fn1 and fn2.</p> </div> <div class="content"><div class='highlight'><pre>enQue.prototype.remove = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">item, amount</span>) </span>{</pre></div></div> </li> <li id="section-13"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Here we extract the items type.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">let</span> type = item.constructor.name; <span class="hljs-keyword">if</span>(type === <span class="hljs-string">'Number'</span>) { <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.que.splice(item, <span class="hljs-number">1</span>); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(type === <span class="hljs-string">"Array"</span>) { amount = amount || <span class="hljs-literal">Infinity</span>; <span class="hljs-keyword">let</span> removed = <span class="hljs-number">0</span>; <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>, l=item.length; i&lt;l; i++) { <span class="hljs-keyword">var</span> check = item[i].constructor.name === <span class="hljs-string">'Function'</span> ? item[i] : item[i].toString(); <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> j=<span class="hljs-number">0</span>, l2=<span class="hljs-keyword">this</span>.que.length; j&lt;l2; j++) {</pre></div></div> </li> <li id="section-14"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>Make sure we dont remove more than amount!</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span>(removed === amount) <span class="hljs-keyword">break</span>; <span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>.que[j] === check) { <span class="hljs-keyword">delete</span> <span class="hljs-keyword">this</span>.que[j]; removed++; } } }</pre></div></div> </li> <li id="section-15"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-15">&#182;</a> </div> <p><strong>returns itself after compacting for use in chaining</strong></p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.compact(); } <span class="hljs-keyword">else</span> { <span class="hljs-keyword">let</span> check = type === <span class="hljs-string">'Function'</span> ? item : item.toString(); amount = amount || <span class="hljs-literal">Infinity</span>; <span class="hljs-keyword">let</span> removed = <span class="hljs-number">0</span>; <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>, l=<span class="hljs-keyword">this</span>.que.length; i&lt;l; i++) {</pre></div></div> </li> <li id="section-16"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>Make sure we dont remove more than amount!</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span>(removed === amount) <span class="hljs-keyword">break</span>; <span class="hljs-keyword">if</span>(check === check.constructor.name === <span class="hljs-string">'Function'</span> ? <span class="hljs-keyword">this</span>.que[i] : <span class="hljs-keyword">this</span>.que[i].toString()) { <span class="hljs-keyword">delete</span> <span class="hljs-keyword">this</span>.que[i] removed++; } }</pre></div></div> </li> <li id="section-17"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-17">&#182;</a> </div> <p><strong>returns itself after compacting for use in chaining</strong></p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.compact(); } }</pre></div></div> </li> <li id="section-18"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-18">&#182;</a> </div> <p><strong>executeQue</strong> Executes the que, you should not need to call this function directly, for example if <code>data</code> doesnt exist you will not be able to consume/output properly. <code>run</code> makes sure data exists. On the offchance you need to bypass the promise system its avialable <code>que.executeQue()</code> but remember to pass in <code>data</code> and <code>done</code> if needed.</p> </div> <div class="content"><div class='highlight'><pre>enQue.prototype.executeQue = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">data, done</span>) </span>{</pre></div></div> </li> <li id="section-19"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-19">&#182;</a> </div> <p>preserve the original callback for potential que rebuilding.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> orig = done;</pre></div></div> </li> <li id="section-20"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-20">&#182;</a> </div> <p><code>i</code> is our iterator, <code>quit</code> and <code>inject</code> are used to check if we need to quit early and resolve the data, or inject <code>Function</code>.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>, quit = <span class="hljs-literal">false</span>, inject = <span class="hljs-literal">false</span>, injectFn = <span class="hljs-literal">false</span>;</pre></div></div> </li> <li id="section-21"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-21">&#182;</a> </div> <p>The <code>nest</code> function allows us to itterate through the que while constantly nesting callbacks.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">this</span>.nest(<span class="hljs-function">(<span class="hljs-params">done, next</span>) =&gt;</span> options =&gt; {</pre></div></div> </li> <li id="section-22"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-22">&#182;</a> </div> <p>Options can be any operation to perform while nesting callbacks. Currently options must be a specific <code>JSON Object</code>, or a <code>Number</code>, if its JSON then it needs a <code>quit</code> or <code>inject</code> property. Otherwise <strong>0</strong> terminates que, exposing the data immitiadtly. A negative Number sends the data to backwards in the que (to a new que <strong>techincally</strong>), Positive Numbers send the data forward, <code>i</code> is current callback index being nested.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span>(options === <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> next = orig; <span class="hljs-keyword">if</span>(options !== data &amp;&amp; options === <span class="hljs-built_in">Object</span>(options)) { <span class="hljs-keyword">if</span>((!options.function &amp;&amp; !options.inject) &amp;&amp; !options.quit) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`<span class="hljs-subst">${options}</span> is not supported, valid fomat could be +n, -n, 0, or, {quit:+n}, {inject:+n,function:Function}`</span>) <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(options.quit) { quit = options.quit; } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(options.inject) { inject = options.inject - <span class="hljs-number">1</span>; injectFn = options.function; } } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(options !== data &amp;&amp; options) {</pre></div></div> </li> <li id="section-23"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-23">&#182;</a> </div> <p>creates a temp que to hold our new que.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">let</span> tmpQue = [];</pre></div></div> </li> <li id="section-24"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-24">&#182;</a> </div> <p>let <code>j</code> be the position we are skipping to. lets say <code>next(-3)</code> was passed, so <code>options = -3</code>. <code>i</code> is the current que spot - 1 that called <code>next(-3)</code>. lets say <code>i</code> was <strong>5</strong>, so we want to go back to <strong>1</strong>. so <code>j = 5 + -3 - (options &lt; 0) = 1</code> so start at position 1, until the end.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> j = i + options - (options &lt; <span class="hljs-number">0</span>); <span class="hljs-keyword">if</span>(!<span class="hljs-keyword">this</span>.que[j<span class="hljs-number">-1</span>]) <span class="hljs-keyword">throw</span> <span class="hljs-string">`<span class="hljs-subst">${options}</span> out of bounds, no que position <span class="hljs-subst">${j}</span> exists.`</span> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> l = <span class="hljs-keyword">this</span>.que.length; j &lt; l; j++) { tmpQue.push(<span class="hljs-keyword">this</span>.que[j]) }</pre></div></div> </li> <li id="section-25"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-25">&#182;</a> </div> <p>sets the que to the one we just built.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">this</span>.que = tmpQue;</pre></div></div> </li> <li id="section-26"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-26">&#182;</a> </div> <p>Apends the original data exposure callback.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">this</span>.que.push(orig) <span class="hljs-keyword">this</span>.executeQue(data);</pre></div></div> </li> <li id="section-27"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-27">&#182;</a> </div> <p>Makes sure the current execution goes nowhere.</p> </div> <div class="content"><div class='highlight'><pre> done = <span class="hljs-function"><span class="hljs-params">()</span>=&gt;</span>{} next = <span class="hljs-function"><span class="hljs-params">()</span>=&gt;</span>{} }</pre></div></div> </li> <li id="section-28"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-28">&#182;</a> </div> <p>if quit is specified, checks if we need to quit and if so sets <code>next</code> to resolve <code>data</code>, otherwise de-increments the checker variable.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span>(quit !== <span class="hljs-literal">false</span>) { <span class="hljs-keyword">if</span>(quit === <span class="hljs-number">0</span>) { next = orig; quit = <span class="hljs-literal">false</span> } <span class="hljs-keyword">else</span> quit--; }</pre></div></div> </li> <li id="section-29"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-29">&#182;</a> </div> <p>if inject is specified, checks if we need to inject the <code>Function</code> if so waits it injects the function <strong>which is NOT part of the que</strong> and hence its execution is not synchronized, this will probably be fixed in the future. calls <code>next</code>, otherwise de-increments checker and calls <code>next</code>.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span>(inject !== <span class="hljs-literal">false</span>) { <span class="hljs-keyword">if</span>(inject === <span class="hljs-number">0</span>) { next(data, done, i++, orig); injectFn(data); injectFn = inject = <span class="hljs-literal">false</span>; } <span class="hljs-keyword">else</span> { inject--; next(data, done, i++, orig); } } <span class="hljs-keyword">else</span> {</pre></div></div> </li> <li id="section-30"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-30">&#182;</a> </div> <p>no special object options were specified just proceeds.</p> </div> <div class="content"><div class='highlight'><pre> next(data, done, i++, orig) } }</pre></div></div> </li> <li id="section-31"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-31">&#182;</a> </div> <p>this sets our initial accumulator to the function done each successive call then creates another function callback nest where the old <code>done</code> becomes the callback of the new <code>done</code> the original <code>done</code> passed in here does nothing more then resolve the data. Which is passed in immidiatly since right after nesting the entire composition is executed.</p> </div> <div class="content"><div class='highlight'><pre> , done)(data); }</pre></div></div> </li> <li id="section-32"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-32">&#182;</a> </div> <p><strong>enQue.run</strong> Creates a promise which resolves when the que ends. <code>que.run(data)</code> or for ques that dont consume data <code>que.run()</code> Since a promise is returns you should then call <code>.then(data=&gt;{})</code> and <code>.catch(error=&gt;{})</code></p> </div> <div class="content"><div class='highlight'><pre>enQue.prototype.run = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>) </span>{</pre></div></div> </li> <li id="section-33"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-33">&#182;</a> </div> <p>Allow ques that dont need to consume data.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span>(!data) data = {}; <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> { <span class="hljs-keyword">try</span> { <span class="hljs-keyword">this</span>.executeQue(data, () =&gt; resolve(data)); } <span class="hljs-keyword">catch</span>(error) { reject(error); }</pre></div></div> </li> <li id="section-34"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-34">&#182;</a> </div> <p><strong>returns a promise which can be used for chaining</strong></p> </div> <div class="content"><div class='highlight'><pre> }) }</pre></div></div> </li> <li id="section-35"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-35">&#182;</a> </div> <p><strong><em>enQue.nest</em></strong> This method should never be called directly unless you know what you are doing. <code>que.nest()</code></p> </div> <div class="content"><div class='highlight'><pre>enQue.prototype.nest = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">callback, orig</span>) </span>{ <span class="hljs-keyword">var</span> que = <span class="hljs-keyword">this</span>.que, pos = que.length - <span class="hljs-number">1</span>, nest;</pre></div></div> </li> <li id="section-36"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-36">&#182;</a> </div> <p>Set the initial done to resolve(data).</p> </div> <div class="content"><div class='highlight'><pre> nest = orig; <span class="hljs-keyword">for</span> (; pos &gt;= <span class="hljs-number">0</span>; pos--) {</pre></div></div> </li> <li id="section-37"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-37">&#182;</a> </div> <p>Now our original done is a callback. which keeps being nested till pos == 0.</p> </div> <div class="content"><div class='highlight'><pre> nest = callback(nest, que[pos]); }</pre></div></div> </li> <li id="section-38"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-38">&#182;</a> </div> <p><strong>returns the fully nested object</strong></p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> nest; }; <span class="hljs-built_in">module</span>.exports = enQue;</pre></div></div> </li> </ul> </div> </body> </html>