enque
Version:
Run asynchonous functions in succession while potentially operating on the same data.
744 lines (509 loc) • 30.7 kB
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">¶</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">¶</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">¶</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">¶</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">¶</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">¶</a>
</div>
<p><strong>enQue.fill</strong> Fills an enQue object with <code>fn</code>‘s <code>n</code> times.
<code>que.fill((_,n)=>{console.log('works');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 < 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">¶</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">¶</a>
</div>
<p><strong>enQue.add</strong> Adds <code>fn</code> to the enQue object.
<code>que.add((_,n,__,i)=>{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 < 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">¶</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">¶</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">¶</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">¶</a>
</div>
<p><strong>enQue.remove</strong> Removes an item from the que.
<code>que.remove("(_,n,__,i)=>{console.log(i)}")</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, "(_,n,__,i)=>{console.log(i)}", 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">¶</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<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<l2; j++) {</pre></div></div>
</li>
<li id="section-14">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-14">¶</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">¶</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<l; i++) {</pre></div></div>
</li>
<li id="section-16">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-16">¶</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">¶</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">¶</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">¶</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">¶</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">¶</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>) =></span>
options => {</pre></div></div>
</li>
<li id="section-22">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-22">¶</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 && options === <span class="hljs-built_in">Object</span>(options)) {
<span class="hljs-keyword">if</span>((!options.function && !options.inject) && !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 && options) {</pre></div></div>
</li>
<li id="section-23">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-23">¶</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">¶</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 < 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 < <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 < 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">¶</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">¶</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">¶</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>=></span>{}
next = <span class="hljs-function"><span class="hljs-params">()</span>=></span>{}
}</pre></div></div>
</li>
<li id="section-28">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-28">¶</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">¶</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">¶</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">¶</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">¶</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=>{})</code>
and <code>.catch(error=>{})</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">¶</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>) =></span> {
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">this</span>.executeQue(data, () => 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">¶</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">¶</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">¶</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 >= <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">¶</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">¶</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>