1 | # Async Endpoint
|
2 |
|
3 | ![Async Endpoint Logo](logo.png)
|
4 |
|
5 | **Asynchronous Endpoints**, especially when paired with a **functional style of programming**,
|
6 | provide a sound method of writing programs in JavaScripts that are
|
7 |
|
8 | - testable
|
9 | - maintainable
|
10 | - extendable
|
11 | - composeable
|
12 | - easy to reason about
|
13 | - standard based*
|
14 |
|
15 | This repository provides a brief intoduction to asynchronous endpoints\*\*, along with a helper library `async-endpoint` to help make a few things easier.
|
16 |
|
17 | ## Table of contents
|
18 |
|
19 | * <a href="#introduction">Introduction</a>
|
20 |
|
21 | * <a href="#introduction-synchronous-endpoints">Synchronous Endpoints</a>
|
22 | * <a href="#introduction-synchronous-iteration">Synchronous Iteration</a>
|
23 | * <a href="#introduction-asynchronous-iteration">Asynchronous Iteration</a>
|
24 | * <a href="#introduction-asynchronous-input">Asynchronous Input</a>
|
25 | * <a href="#import">Import</a>
|
26 | * <a href="#application-programming-interface">API</a>
|
27 | # <a name="introduction"></a>Introduction
|
28 |
|
29 | Many programming languages use the concept of functions as [entry points](https://en.wikipedia.org/wiki/Entry_point) to transfer control between programs.
|
30 |
|
31 | ## <a name="introduction-synchronous-endpoints"></a> Synchronous Endpoints
|
32 |
|
33 | In javascript, this is as simple as writing a function and calling it:
|
34 |
|
35 | **Example 1**
|
36 |
|
37 | ```javascript
|
38 | const program = function() {
|
39 | console.log("hello world");
|
40 | };
|
41 |
|
42 | program();
|
43 | //logs "hello world"
|
44 | ```
|
45 |
|
46 | Taking a queue from functional programming, we can remove the logging side affect from the main program
|
47 | into a separate **render** function that logs the result retuned from running:
|
48 |
|
49 | **Example 2**
|
50 |
|
51 | ```javascript
|
52 | const render = console.log;
|
53 |
|
54 | const program = function() {
|
55 | return "hello world";
|
56 | };
|
57 |
|
58 | render(program());
|
59 | //logs "hello world"
|
60 | ```
|
61 |
|
62 | ## <a name="introduction-synchronous-iteration"></a> Synchronous Iteration
|
63 |
|
64 | Provided that our render function expects an iterator,
|
65 | We can construct our program with a **generator function** to yeild multiple results:
|
66 |
|
67 | **Example 3**
|
68 |
|
69 | ```javascript
|
70 | const render = iterator => {
|
71 | //as the result is an iterator
|
72 | //we iterate though it and log each subsequent result
|
73 | for (const result of iterator) {
|
74 | console.log(result);
|
75 | }
|
76 | };
|
77 |
|
78 | const program = function*() {
|
79 | yield "hello";
|
80 | yield "world";
|
81 | };
|
82 |
|
83 | render(program());
|
84 | //logs "hello"
|
85 | //logs "world"
|
86 | ```
|
87 |
|
88 | ## <a name="introduction-asynchronous-iteration"></a> Asynchronous Iteration
|
89 |
|
90 | When using **asynchronous generators**, we can **await** asynchronous APIs,
|
91 | though we must again make sure to modify our fetch function.
|
92 |
|
93 | **Example 4**
|
94 |
|
95 | ```javascript
|
96 | const render = async asynchronousIterator => {
|
97 | //we use the "for await" construct for Asynchronous Iterators
|
98 | for await (const result of asynchronousIterator) {
|
99 | console.log(result);
|
100 | }
|
101 | };
|
102 |
|
103 | const program = async function*() {
|
104 | yield "fetching...";
|
105 | yield await fetch("https://www.google.com");
|
106 | yield "results fetched.";
|
107 | };
|
108 | render(program());
|
109 | //logs "fetching..."
|
110 | //logs result from fetch.
|
111 | //logs "results fetched."
|
112 | ```
|
113 |
|
114 | ## <a name="introduction-asynchronous-input"></a> Asynchronous Input and Interactive Programs
|
115 |
|
116 | With a few small tricks, asynchronous generators can as fully interactive programs.
|
117 |
|
118 | We'll need a pair of functions: well call them "request" and "respond".
|
119 |
|
120 | When a program calles _request_, it will return a promise.
|
121 | This promise will then be fulfilled with the input of the next call to _respond_.
|
122 | While you can create these functions yourself,
|
123 | a method of creating them is included with the `async-endpoint` library.
|
124 |
|
125 | ```javascript
|
126 | import { channel } from "async-endpoint";
|
127 | const [request, respond] = channel();
|
128 | ```
|
129 |
|
130 | By convention, we'll pass two arguments to our asynchronous generator function:
|
131 |
|
132 | - an _init_ object, which may or may not be ignored
|
133 | - the aforementioned _request_ function
|
134 |
|
135 | ```javascript
|
136 | const program = async function *(init, request){
|
137 | ...
|
138 | }
|
139 | ```
|
140 |
|
141 | Finally, we need to connect the _respond_ object to user input.
|
142 | If running in a browser, you could simply attach it to the window object:
|
143 |
|
144 | ```javascript
|
145 | window.respond = respond;
|
146 | ```
|
147 |
|
148 | Or, if running in node, you can use the included `inputConsole` function:
|
149 |
|
150 | ```javascript
|
151 | import { inputConsole } from "async-endpoint";
|
152 | inputConsole(respond);
|
153 | ```
|
154 |
|
155 | Puttig it all together, we can write an interactive program like this:
|
156 | (Note that instead of defining a render function, we're using the
|
157 | generic `renderer` from the `async-endpoit` library instead of writing our own this time).
|
158 |
|
159 | **Example 5**
|
160 |
|
161 | ```javascript
|
162 | import { channel, inputConsole, renderer } from "async-endpoint";
|
163 |
|
164 | const render = renderer();
|
165 |
|
166 | const program = async function*(init, request) {
|
167 | yield "What's your name?";
|
168 | yield `Hello ${await request()}`;
|
169 | };
|
170 |
|
171 | const [request, respond] = channel();
|
172 |
|
173 | inputConsole(respond);
|
174 |
|
175 | render(program(undefined, request)); //the init object will be ignored
|
176 | //logs "
|
177 | ```
|
178 | # <a name="import"></a>Import
|
179 |
|
180 | There are a few ways to import this into your project.
|
181 |
|
182 | ## Pre-Ecmascript Modules
|
183 |
|
184 | ### Common JS
|
185 |
|
186 | The package's main file is a compiled common JS file.
|
187 |
|
188 | ```javascript
|
189 | const AsyncEndpoint = require("async-endpoint");
|
190 | ```
|
191 |
|
192 | ```javascript
|
193 | const AsyncEndpoint = require("async-endpoint/common.js"); //also works
|
194 | ```
|
195 |
|
196 | This _should_ work with file bundlers, though I haven't had a chance to test it.
|
197 |
|
198 | ```javascript
|
199 | import * as AsyncEndpoint from = "async-endpoint/common.js";
|
200 | ```
|
201 |
|
202 | ### Browser
|
203 |
|
204 | ```html
|
205 | <script src = ".../async-endpoint/browser.js"></script>
|
206 | <script>
|
207 | alert(typeof window.AsyncEndpoint);
|
208 | </script>
|
209 | ```
|
210 |
|
211 | ## Ecmascript Modules
|
212 |
|
213 | Ecmascript modules are available in two flavors of ecmascript modules:
|
214 |
|
215 | ### MJS
|
216 |
|
217 | In a node application, the "import" keyword can be used to import the package.
|
218 |
|
219 | ```javascript
|
220 | //index.mjs
|
221 | import * as AsyncEndpoint from "async-endpoint/mjs";
|
222 | ```
|
223 |
|
224 | As of this writing, node requires the the "experimental-modules" and
|
225 | "harmony_async_iteration" flags to be set, but this will change once a the
|
226 | "import" and "asynchronous iterator" features hae landed.
|
227 |
|
228 | ```bash
|
229 | node --experimental-modules --harmony_async_iteration index.mjs
|
230 | ```
|
231 |
|
232 | If you wish to avoid experimental the features, use the above **common.js** module.
|
233 |
|
234 | ### JS
|
235 |
|
236 | In a browser application, the "import" keyword can be used to import the package.
|
237 |
|
238 | When using ".mjs" files, a server may fail to serve the proper "application/javascript"
|
239 | mime type causing the application to fail. As such, the "js" folder is included.
|
240 |
|
241 |
|
242 | ```html
|
243 | <script>
|
244 | import * as AsyncEndpoint from "async-endpoint/js";
|
245 | <script>
|
246 | alert(typeof window.AsyncEndpoint);
|
247 | </script>
|
248 | </script>
|
249 | ```
|
250 |
|
251 | As of this writing, only Chrome supports the necessary import and asynchronous interation features
|
252 | necessary to get this to work.
|
253 |
|
254 | To ensure compatibility with other browsers use the above **browser.js** module.
|
255 | You can also re-bundle either the flow, js, or mjs folders.
|
256 |
|
257 | # <a name="application-programming-interface"></a> API
|
258 | ## Members
|
259 |
|
260 | <dl>
|
261 | <dt><a href="#channel">channel</a> ⇒ <code><a href="#AsyncPair">AsyncPair</a></code></dt>
|
262 | <dd><p>creates a pair of asynchronous functions used to transfer objects between programs</p>
|
263 | </dd>
|
264 | </dl>
|
265 |
|
266 | ## Functions
|
267 |
|
268 | <dl>
|
269 | <dt><a href="#composePrograms">composePrograms(request, ...programs)</a> ⇒ <code>AsynchornousIterator</code></dt>
|
270 | <dd><p>composes programs sequentially with a single input</p>
|
271 | </dd>
|
272 | <dt><a href="#creates an iterator whose values are mapped from another">creates an iterator whose values are mapped from another(iterator, mapper)</a> ⇒ <code>AsynchornousIterator</code></dt>
|
273 | <dd></dd>
|
274 | <dt><a href="#executes a provided funcition for each item of an iterator">executes a provided funcition for each item of an iterator(iterator, handler)</a> ⇒ <code>undefined</code></dt>
|
275 | <dd></dd>
|
276 | <dt><a href="#filter">filter(iterator, filterer)</a> ⇒ <code>AsynchornousIterator</code></dt>
|
277 | <dd><p>creates an iterator whose values are filtered from another</p>
|
278 | </dd>
|
279 | <dt><a href="#reduce">reduce(iterator, reducer, [inital], [condition], [resetInitial])</a> ⇒ <code>AsynchornousIterator</code></dt>
|
280 | <dd><p>creates an iterator whose values are reduced from another</p>
|
281 | </dd>
|
282 | <dt><a href="#pause">pause(milliseconds, value)</a> ⇒ <code>Promise</code></dt>
|
283 | <dd><p>returns a resolved promise after a given amount of time
|
284 | useful for pausing asynchronous programs</p>
|
285 | </dd>
|
286 | <dt><a href="#composeAsyncTransformer">composeAsyncTransformer(last, first)</a> ⇒ <code><a href="#AsyncTransformer">AsyncTransformer</a></code></dt>
|
287 | <dd><p>composes two asynchoronous transformers</p>
|
288 | </dd>
|
289 | <dt><a href="#createQueue">createQueue(...initial)</a> ⇒ <code><a href="#PushPair">PushPair</a></code></dt>
|
290 | <dd><p>create a queue iterator</p>
|
291 | </dd>
|
292 | <dt><a href="#createStack">createStack(...initial)</a> ⇒ <code><a href="#PushPair">PushPair</a></code></dt>
|
293 | <dd><p>create a stack iterator</p>
|
294 | </dd>
|
295 | <dt><a href="#createProgramQueue">createProgramQueue()</a> ⇒ <code><a href="#PushPair">PushPair</a></code></dt>
|
296 | <dd><p>identity program that outputs what ever is input
|
297 | Like "queue", but accepts program as input</p>
|
298 | </dd>
|
299 | <dt><a href="#createProgramStack">createProgramStack()</a> ⇒ <code><a href="#PushPair">PushPair</a></code></dt>
|
300 | <dd><p>identity program that outputs what ever is input
|
301 | Like "queue", but accepts program as input</p>
|
302 | </dd>
|
303 | <dt><a href="#take">take(iterator, num, [skip])</a> ⇒ <code>Promise.<Array></code></dt>
|
304 | <dd><p>extract items from iterator as array</p>
|
305 | </dd>
|
306 | <dt><a href="#takeWhile">takeWhile(iterator, accept, [skip])</a> ⇒ <code>Promise.<Array></code></dt>
|
307 | <dd><p>extract first set of items that match a given condition as an array</p>
|
308 | </dd>
|
309 | <dt><a href="#identity">identity([delay], request)</a> ⇒ <code>AsynchronousIterator</code></dt>
|
310 | <dd><p>program that outputs what ever is put throught</p>
|
311 | </dd>
|
312 | <dt><a href="#continuousOutput">continuousOutput([sample])</a> ⇒ <code>AsynchronousIterator</code></dt>
|
313 | <dd><p>program that takes no input and contiuously outputs result of calling function</p>
|
314 | </dd>
|
315 | <dt><a href="#renderer">renderer([...targets])</a> ⇒ <code><a href="#AsyncRenderFunction">AsyncRenderFunction</a></code></dt>
|
316 | <dd><p>creates a render function that renders yeilded results from programs
|
317 | to any number of target functions. If no targets are given, objects will be rendered
|
318 | using "console.log"
|
319 | Can be used as a "passthrough" (see "createQueue" example)</p>
|
320 | </dd>
|
321 | <dt><a href="#tee">tee(...programs)</a> ⇒ <code><a href="#AsyncRenderFunction">AsyncRenderFunction</a></code></dt>
|
322 | <dd><p>creates a render function whos's values are teed on to given
|
323 | It may be advantageous to use this along side a programQueue</p>
|
324 | </dd>
|
325 | <dt><a href="#inputConsole">inputConsole(respond)</a></dt>
|
326 | <dd><p>send input typed into console to a PairedRespond function</p>
|
327 | </dd>
|
328 | <dt><a href="#inputPipe">inputPipe(respond)</a></dt>
|
329 | <dd><p>send input piped to console to a PairedRespond function</p>
|
330 | </dd>
|
331 | </dl>
|
332 |
|
333 | ## Typedefs
|
334 |
|
335 | <dl>
|
336 | <dt><a href="#PairedRequest">PairedRequest</a> ⇒ <code>Promise.<*></code></dt>
|
337 | <dd><p>a function that receives it's response from a paired PairedRespond function</p>
|
338 | </dd>
|
339 | <dt><a href="#PairedRespond">PairedRespond</a> : <code>function</code></dt>
|
340 | <dd><p>a function that sends it's input to a paired PairedRequest function</p>
|
341 | </dd>
|
342 | <dt><a href="#AsyncPair">AsyncPair</a> : <code>Array</code></dt>
|
343 | <dd><p>a pair of paired PairedRequest and PairedRespond functions</p>
|
344 | </dd>
|
345 | <dt><a href="#AsyncTransformer">AsyncTransformer</a> ⇒ <code>*</code></dt>
|
346 | <dd><p>stateless asynchronous function that transforms input without side effects</p>
|
347 | </dd>
|
348 | <dt><a href="#Program">Program</a> ⇒ <code>AsynchronousIterator</code></dt>
|
349 | <dd><p>an iteractive program</p>
|
350 | </dd>
|
351 | <dt><a href="#AsyncRenderFunction">AsyncRenderFunction</a> : <code>function</code></dt>
|
352 | <dd><p>a function that renders values from a given [Asynchronous] Iterator</p>
|
353 | </dd>
|
354 | <dt><a href="#PushPair">PushPair</a> : <code>Array</code></dt>
|
355 | <dd><p>an iterator and a paired function to add to it</p>
|
356 | </dd>
|
357 | </dl>
|
358 |
|
359 | <a name="channel"></a>
|
360 |
|
361 | ## channel ⇒ [<code>AsyncPair</code>](#AsyncPair)
|
362 | creates a pair of asynchronous functions used to transfer objects between programs
|
363 |
|
364 | **Kind**: global variable
|
365 | **Returns**: [<code>AsyncPair</code>](#AsyncPair) - array of paired functions
|
366 | **Example**
|
367 | ```js
|
368 | import {channel} from "async-endpoint";
|
369 | const [request, respond] = channel();
|
370 | const main = async()=>{
|
371 | setTimeout(()=>{
|
372 | respond("hello");
|
373 | })
|
374 | console.log(await request());
|
375 | }
|
376 | main();
|
377 | //logs "hello"
|
378 | ```
|
379 | <a name="composePrograms"></a>
|
380 |
|
381 | ## composePrograms(request, ...programs) ⇒ <code>AsynchornousIterator</code>
|
382 | composes programs sequentially with a single input
|
383 |
|
384 | **Kind**: global function
|
385 | **Returns**: <code>AsynchornousIterator</code> - resulting iterator
|
386 |
|
387 | | Param | Type | Description |
|
388 | | --- | --- | --- |
|
389 | | request | [<code>PairedRequest</code>](#PairedRequest) | request function for input |
|
390 | | ...programs | [<code>Program</code>](#Program) | programs to be composed sequentially |
|
391 |
|
392 | **Example**
|
393 | ```js
|
394 | import {composePrograms} from "async-endpoint";
|
395 | import porgram1, program1, program3 from "....js";
|
396 | const [request, respond] = channel();
|
397 | const program = composePrograms(request, program1, program2, program3);
|
398 | window.respond = respond;
|
399 | ```
|
400 | <a name="creates an iterator whose values are mapped from another"></a>
|
401 |
|
402 | ## creates an iterator whose values are mapped from another(iterator, mapper) ⇒ <code>AsynchornousIterator</code>
|
403 | **Kind**: global function
|
404 | **Returns**: <code>AsynchornousIterator</code> - resulting iterator
|
405 |
|
406 | | Param | Type | Description |
|
407 | | --- | --- | --- |
|
408 | | iterator | <code>AsynchornousIterator</code> | iterator to be mapped |
|
409 | | mapper | [<code>AsyncTransformer</code>](#AsyncTransformer) | transformation for individual items |
|
410 |
|
411 | **Example**
|
412 | ```js
|
413 | import {map, continuousOutput}, from "async-endpoint";
|
414 | let i = 0;
|
415 | const mapped = map(continuousOutput(()=>i++), (n) => n + 2);
|
416 | const main = async ()=>{
|
417 | for await(item of mapped){
|
418 | console.log(item);
|
419 | }
|
420 | }
|
421 | main();
|
422 | logs "2"
|
423 | logs "3"
|
424 | logs "4"
|
425 | ...
|
426 | ```
|
427 | <a name="executes a provided funcition for each item of an iterator"></a>
|
428 |
|
429 | ## executes a provided funcition for each item of an iterator(iterator, handler) ⇒ <code>undefined</code>
|
430 | **Kind**: global function
|
431 |
|
432 | | Param | Type | Description |
|
433 | | --- | --- | --- |
|
434 | | iterator | <code>AsynchornousIterator</code> | iterator |
|
435 | | handler | [<code>AsyncTransformer</code>](#AsyncTransformer) | provided function |
|
436 |
|
437 | **Example**
|
438 | ```js
|
439 | import {forEach, continuousOutput}, from "async-endpoint";
|
440 | let i = 0;
|
441 | forEach(continuousOutput(()=>i++, console.log));
|
442 | main();
|
443 | logs "2"
|
444 | logs "3"
|
445 | logs "4"
|
446 | ...
|
447 | ```
|
448 | <a name="filter"></a>
|
449 |
|
450 | ## filter(iterator, filterer) ⇒ <code>AsynchornousIterator</code>
|
451 | creates an iterator whose values are filtered from another
|
452 |
|
453 | **Kind**: global function
|
454 | **Returns**: <code>AsynchornousIterator</code> - filtered iterator
|
455 |
|
456 | | Param | Type | Description |
|
457 | | --- | --- | --- |
|
458 | | iterator | <code>AsynchornousIterator</code> | iterator to be filtered |
|
459 | | filterer | <code>function</code> | boolean filtering function |
|
460 |
|
461 | **Example**
|
462 | ```js
|
463 | import {filter, continuousOutput} from "async-endpoint";
|
464 | let i = 0;
|
465 | const filtered =filter(continuousOutput(()=>i++), (n)=>n%2);
|
466 | const main = async ()=>{
|
467 | for await(item of filtered){
|
468 | console.log(item);
|
469 | }
|
470 | }
|
471 | main();
|
472 | logs "1"
|
473 | logs "3"
|
474 | logs "5"
|
475 | ```
|
476 | <a name="reduce"></a>
|
477 |
|
478 | ## reduce(iterator, reducer, [inital], [condition], [resetInitial]) ⇒ <code>AsynchornousIterator</code>
|
479 | creates an iterator whose values are reduced from another
|
480 |
|
481 | **Kind**: global function
|
482 | **Returns**: <code>AsynchornousIterator</code> - reduced iterator
|
483 |
|
484 | | Param | Type | Default | Description |
|
485 | | --- | --- | --- | --- |
|
486 | | iterator | <code>AsynchornousIterator</code> | | iterator to be reduced |
|
487 | | reducer | <code>function</code> | | reducing function |
|
488 | | [inital] | <code>\*</code> | | initial object to reduce into |
|
489 | | [condition] | <code>function</code> | <code>(item, initial) => false</code> | boolean filtering function indicating when to start new reduction phase |
|
490 | | [resetInitial] | <code>function</code> | <code>()=>initial</code> | method to reset/replace initial reduction object |
|
491 |
|
492 | **Example**
|
493 | ```js
|
494 | import {reduce, continuousOutput} from "async-endpoint";
|
495 | let i = 0;
|
496 | const reduced = reduce(continuousOutput(()=>i++) , (previous, current)=>previous.push(current),[], (x)=!(x%5), ()=>([]));
|
497 | const main = async ()=>{
|
498 | for await(item of reduced){
|
499 | console.log(item);
|
500 | }
|
501 | }
|
502 | main();
|
503 | logs "[0]"
|
504 | logs "[1, 2, 3, 4, 5]"
|
505 | ...
|
506 | ```
|
507 | <a name="pause"></a>
|
508 |
|
509 | ## pause(milliseconds, value) ⇒ <code>Promise</code>
|
510 | returns a resolved promise after a given amount of time
|
511 | useful for pausing asynchronous programs
|
512 |
|
513 | **Kind**: global function
|
514 | **Returns**: <code>Promise</code> - promise fulfilled with value
|
515 |
|
516 | | Param | Type | Description |
|
517 | | --- | --- | --- |
|
518 | | milliseconds | <code>Number</code> | time to pause |
|
519 | | value | <code>\*</code> | optional returned value |
|
520 |
|
521 | **Example**
|
522 | ```js
|
523 | import {pause} from "async-endopint.js";
|
524 | const main = async ()=>{
|
525 | console.log("hello");
|
526 | await pause(1000);
|
527 | console.log("goodbye");
|
528 | }
|
529 | main();
|
530 | //logs "hello"
|
531 | //logs "goodbye" (after 1 second)
|
532 | ```
|
533 | <a name="composeAsyncTransformer"></a>
|
534 |
|
535 | ## composeAsyncTransformer(last, first) ⇒ [<code>AsyncTransformer</code>](#AsyncTransformer)
|
536 | composes two asynchoronous transformers
|
537 |
|
538 | **Kind**: global function
|
539 | **Returns**: [<code>AsyncTransformer</code>](#AsyncTransformer) - asynchonous compositon of current and pre
|
540 |
|
541 | | Param | Type | Description |
|
542 | | --- | --- | --- |
|
543 | | last | [<code>AsyncTransformer</code>](#AsyncTransformer) | transformer to apply last |
|
544 | | first | [<code>AsyncTransformer</code>](#AsyncTransformer) | transformer to apply first |
|
545 |
|
546 | **Example**
|
547 | ```js
|
548 | import {composeAsyncTransformer} from "async-endopint.js";
|
549 | const t1 = async (x)=>`<${x}>`;
|
550 | const t2 = async (x)=>`[${x}]`;
|
551 | const t = composeAsyncTransformer(t1, t2);
|
552 | t("hello").then(console.log);
|
553 | //logs "<[hello]>"
|
554 | ```
|
555 | <a name="createQueue"></a>
|
556 |
|
557 | ## createQueue(...initial) ⇒ [<code>PushPair</code>](#PushPair)
|
558 | create a queue iterator
|
559 |
|
560 | **Kind**: global function
|
561 | **Returns**: [<code>PushPair</code>](#PushPair) - queue and push function
|
562 |
|
563 | | Param | Type | Description |
|
564 | | --- | --- | --- |
|
565 | | ...initial | <code>\*</code> | initial items in queue |
|
566 |
|
567 | **Example**
|
568 | ```js
|
569 | import {createQueue, channel, renderer, renderer as createPassThrough} from "async-endpoint";
|
570 | import porgram1, program1, program3 from "....js";
|
571 | const [queue, push] createQueue();
|
572 | const passthrough = createPassThrough(push);
|
573 | passthrough(porgram1(), program2(), program3());
|
574 | const render = renderer();
|
575 | render(queue);
|
576 | ```
|
577 | <a name="createStack"></a>
|
578 |
|
579 | ## createStack(...initial) ⇒ [<code>PushPair</code>](#PushPair)
|
580 | create a stack iterator
|
581 |
|
582 | **Kind**: global function
|
583 | **Returns**: [<code>PushPair</code>](#PushPair) - stack and push function
|
584 |
|
585 | | Param | Type | Description |
|
586 | | --- | --- | --- |
|
587 | | ...initial | <code>\*</code> | initial items on stack |
|
588 |
|
589 | **Example**
|
590 | ```js
|
591 | import {createStack, channel, renderer, renderer as createPassThrough} from "async-endpoint";
|
592 | import porgram1, program1, program3 from "....js";
|
593 | const [stack, push] createStack();
|
594 | const passthrough = createPassThrough(push);
|
595 | passthrough(porgram1(), program2(), program3());
|
596 | const render = renderer();
|
597 | render(stack);
|
598 | ```
|
599 | <a name="createProgramQueue"></a>
|
600 |
|
601 | ## createProgramQueue() ⇒ [<code>PushPair</code>](#PushPair)
|
602 | identity program that outputs what ever is input
|
603 | Like "queue", but accepts program as input
|
604 |
|
605 | **Kind**: global function
|
606 | **Returns**: [<code>PushPair</code>](#PushPair) - iterator and push function
|
607 | **Example**
|
608 | ```js
|
609 | import {createProgramQueue, channel, renderer} from "async-endpoint";
|
610 | import porgram1, program1, program3 from "....js";
|
611 | const [queue, push] = createProgramQueue();
|
612 | push(porgram1(), program2(), program3());
|
613 | const render = renderer();
|
614 | render(queue);
|
615 | ```
|
616 | <a name="createProgramStack"></a>
|
617 |
|
618 | ## createProgramStack() ⇒ [<code>PushPair</code>](#PushPair)
|
619 | identity program that outputs what ever is input
|
620 | Like "queue", but accepts program as input
|
621 |
|
622 | **Kind**: global function
|
623 | **Returns**: [<code>PushPair</code>](#PushPair) - iterator and push function
|
624 | **Example**
|
625 | ```js
|
626 | import {createProgramStack, channel, renderer} from "async-endpoint";
|
627 | import porgram1, program1, program3 from "....js";
|
628 | const [stack, push] = createProgramStack();
|
629 | push(porgram1(), program2(), program3());
|
630 | const render = renderer();
|
631 | render(stack);
|
632 | ```
|
633 | <a name="take"></a>
|
634 |
|
635 | ## take(iterator, num, [skip]) ⇒ <code>Promise.<Array></code>
|
636 | extract items from iterator as array
|
637 |
|
638 | **Kind**: global function
|
639 | **Returns**: <code>Promise.<Array></code> - stack and push function
|
640 |
|
641 | | Param | Type | Default | Description |
|
642 | | --- | --- | --- | --- |
|
643 | | iterator | <code>AsynchronousIterator</code> | | iterator from which to take |
|
644 | | num | <code>Number</code> | | number of items to take from iterator |
|
645 | | [skip] | <code>Number</code> | <code>0</code> | number of items to skip before taking |
|
646 |
|
647 | **Example**
|
648 | ```js
|
649 | import {take, continuousOutput} from "async-endpoint";
|
650 | let i = 0;
|
651 | take(continuousOutput(()=>i++), 3,1).then(taken=>console.log(taken));
|
652 | //logs "[1,2,3]"
|
653 | ```
|
654 | <a name="takeWhile"></a>
|
655 |
|
656 | ## takeWhile(iterator, accept, [skip]) ⇒ <code>Promise.<Array></code>
|
657 | extract first set of items that match a given condition as an array
|
658 |
|
659 | **Kind**: global function
|
660 | **Returns**: <code>Promise.<Array></code> - stack and push function
|
661 |
|
662 | | Param | Type | Default | Description |
|
663 | | --- | --- | --- | --- |
|
664 | | iterator | <code>AsynchronousIterator</code> | | iterator from which to take |
|
665 | | accept | <code>function</code> | | boolean filtering function indicating whether to allow item |
|
666 | | [skip] | <code>Number</code> | <code>0</code> | number of items to skip before taking |
|
667 |
|
668 | **Example**
|
669 | ```js
|
670 | import {takeWhile, continuousOutput} from "async-endpoint";
|
671 | let i = 0;
|
672 | takeWhile(continuousOutput(()=>i++), x => x < 5, 2).then(taken=>console.log(taken));
|
673 | //logs "[2,3,4]"
|
674 | ```
|
675 | <a name="identity"></a>
|
676 |
|
677 | ## identity([delay], request) ⇒ <code>AsynchronousIterator</code>
|
678 | program that outputs what ever is put throught
|
679 |
|
680 | **Kind**: global function
|
681 | **Returns**: <code>AsynchronousIterator</code> - resulting iterator
|
682 |
|
683 | | Param | Type | Default | Description |
|
684 | | --- | --- | --- | --- |
|
685 | | [delay] | <code>\*</code> | <code>0</code> | delay between sending output |
|
686 | | request | [<code>PairedRequest</code>](#PairedRequest) | | request function for input |
|
687 |
|
688 | **Example**
|
689 | ```js
|
690 | import {identity, renderer channel} from "async-endpoint";
|
691 | const [request, respond] = channel();
|
692 | identity(undefined, request);
|
693 | window.respond = respond
|
694 | ```
|
695 | <a name="continuousOutput"></a>
|
696 |
|
697 | ## continuousOutput([sample]) ⇒ <code>AsynchronousIterator</code>
|
698 | program that takes no input and contiuously outputs result of calling function
|
699 |
|
700 | **Kind**: global function
|
701 | **Returns**: <code>AsynchronousIterator</code> - resulting iterator
|
702 |
|
703 | | Param | Type | Default | Description |
|
704 | | --- | --- | --- | --- |
|
705 | | [sample] | <code>\*</code> | <code>()=>{}</code> | function whose result to output |
|
706 |
|
707 | **Example**
|
708 | ```js
|
709 | import {continuousOutput, renderer} from "async-endpoint";
|
710 | const render = renderer();
|
711 | render(continuousOutput(()=>"hello"))
|
712 | logs "hello" (continously)
|
713 | ...
|
714 | ```
|
715 | <a name="renderer"></a>
|
716 |
|
717 | ## renderer([...targets]) ⇒ [<code>AsyncRenderFunction</code>](#AsyncRenderFunction)
|
718 | creates a render function that renders yeilded results from programs
|
719 | to any number of target functions. If no targets are given, objects will be rendered
|
720 | using "console.log"
|
721 | Can be used as a "passthrough" (see "createQueue" example)
|
722 |
|
723 | **Kind**: global function
|
724 | **Returns**: [<code>AsyncRenderFunction</code>](#AsyncRenderFunction) - asychronous render function
|
725 |
|
726 | | Param | Type | Description |
|
727 | | --- | --- | --- |
|
728 | | [...targets] | <code>function</code> | request function for input |
|
729 |
|
730 | **Example**
|
731 | ```js
|
732 | import {renderer, continuousOutput} from "async-input.js";
|
733 | const render = renderer();
|
734 | render(continuousOutput);
|
735 | //logs "0"
|
736 | //logs "1"
|
737 | ...
|
738 | ```
|
739 | <a name="tee"></a>
|
740 |
|
741 | ## tee(...programs) ⇒ [<code>AsyncRenderFunction</code>](#AsyncRenderFunction)
|
742 | creates a render function whos's values are teed on to given
|
743 | It may be advantageous to use this along side a programQueue
|
744 |
|
745 | **Kind**: global function
|
746 | **Returns**: [<code>AsyncRenderFunction</code>](#AsyncRenderFunction) - asychronous render function
|
747 |
|
748 | | Param | Type | Description |
|
749 | | --- | --- | --- |
|
750 | | ...programs | [<code>Program</code>](#Program) | programs to be sent values |
|
751 |
|
752 | **Example**
|
753 | ```js
|
754 | import {tee, continousOutput, renderer} from "async-endpoint";
|
755 | import porgram1, program1, program3 from "....js";
|
756 | const instance1 = program1();
|
757 | const instance2 = program2();
|
758 | const instance3 = program3();
|
759 | const render = renderer();
|
760 | render(instance1, instance2, instance3)
|
761 | const renderTee = tee(porgram1, program1, program3)
|
762 | renderTee(continousOutput())
|
763 | ```
|
764 | <a name="inputConsole"></a>
|
765 |
|
766 | ## inputConsole(respond)
|
767 | send input typed into console to a PairedRespond function
|
768 |
|
769 | **Kind**: global function
|
770 |
|
771 | | Param | Type | Description |
|
772 | | --- | --- | --- |
|
773 | | respond | [<code>PairedRespond</code>](#PairedRespond) | request function for input |
|
774 |
|
775 | **Example**
|
776 | ```js
|
777 | import {inputConsole, identity, channel, renderer} from "async-endpoint";
|
778 | const [request, respond] = creteAsyncPair();
|
779 | const render = renderer();
|
780 | render(identity(undefined, request))
|
781 | inputConsole(respond);
|
782 | ```
|
783 | <a name="inputPipe"></a>
|
784 |
|
785 | ## inputPipe(respond)
|
786 | send input piped to console to a PairedRespond function
|
787 |
|
788 | **Kind**: global function
|
789 |
|
790 | | Param | Type | Description |
|
791 | | --- | --- | --- |
|
792 | | respond | [<code>PairedRespond</code>](#PairedRespond) | request function for input |
|
793 |
|
794 | **Example**
|
795 | ```js
|
796 | import {inputPipe, identity, channel, renderer} from "async-endpoint";
|
797 | const [request, respond] = creteAsyncPair();
|
798 | const render = renderer();
|
799 | render(identity(undefined, request))
|
800 | inputPipe(respond);
|
801 | ```
|
802 | <a name="PairedRequest"></a>
|
803 |
|
804 | ## PairedRequest ⇒ <code>Promise.<\*></code>
|
805 | a function that receives it's response from a paired PairedRespond function
|
806 |
|
807 | **Kind**: global typedef
|
808 | **Returns**: <code>Promise.<\*></code> - response from respond reunction
|
809 | <a name="PairedRespond"></a>
|
810 |
|
811 | ## PairedRespond : <code>function</code>
|
812 | a function that sends it's input to a paired PairedRequest function
|
813 |
|
814 | **Kind**: global typedef
|
815 |
|
816 | | Param | Type | Description |
|
817 | | --- | --- | --- |
|
818 | | response | <code>\*</code> | response for request function |
|
819 |
|
820 | <a name="AsyncPair"></a>
|
821 |
|
822 | ## AsyncPair : <code>Array</code>
|
823 | a pair of paired PairedRequest and PairedRespond functions
|
824 |
|
825 | **Kind**: global typedef
|
826 | **Properties**
|
827 |
|
828 | | Name | Type | Description |
|
829 | | --- | --- | --- |
|
830 | | 0 | [<code>PairedRequest</code>](#PairedRequest) | request function |
|
831 | | 1 | [<code>PairedRespond</code>](#PairedRespond) | respond function |
|
832 |
|
833 | <a name="AsyncTransformer"></a>
|
834 |
|
835 | ## AsyncTransformer ⇒ <code>\*</code>
|
836 | stateless asynchronous function that transforms input without side effects
|
837 |
|
838 | **Kind**: global typedef
|
839 | **Returns**: <code>\*</code> - transformed input
|
840 |
|
841 | | Param | Type | Description |
|
842 | | --- | --- | --- |
|
843 | | input | <code>\*</code> | input |
|
844 |
|
845 | <a name="Program"></a>
|
846 |
|
847 | ## Program ⇒ <code>AsynchronousIterator</code>
|
848 | an iteractive program
|
849 |
|
850 | **Kind**: global typedef
|
851 | **Returns**: <code>AsynchronousIterator</code> - asynchronous iterator result
|
852 |
|
853 | | Param | Type | Description |
|
854 | | --- | --- | --- |
|
855 | | init | <code>\*</code> | |
|
856 | | request | [<code>PairedRequest</code>](#PairedRequest) | request function for input |
|
857 |
|
858 | <a name="AsyncRenderFunction"></a>
|
859 |
|
860 | ## AsyncRenderFunction : <code>function</code>
|
861 | a function that renders values from a given [Asynchronous] Iterator
|
862 |
|
863 | **Kind**: global typedef
|
864 |
|
865 | | Param | Type |
|
866 | | --- | --- |
|
867 | | program_return; | <code>AsynchronousIterator</code> |
|
868 |
|
869 | <a name="PushPair"></a>
|
870 |
|
871 | ## PushPair : <code>Array</code>
|
872 | an iterator and a paired function to add to it
|
873 |
|
874 | **Kind**: global typedef
|
875 | **Properties**
|
876 |
|
877 | | Name | Type | Description |
|
878 | | --- | --- | --- |
|
879 | | 0 | <code>AsynchornousIterator</code> | iterator |
|
880 | | 1 | <code>function</code> | function used to add to iterator |
|
881 |
|