60fps with Functional Programming in idle time
Tags: javascript, webdev, frontend
Published: 2020-07-03 06:39:52

[![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qc7xww7co3re0jr8weh1.png)](http://js-coroutines.com)

[js-coroutines](http://js-coroutines.com) has been able to process standard functions like parsing and stringifying JSON, or compressing data in idle time since it was launched - splitting up jobs over multiple frames so that everything stays smooth at 60fps - it now has the ability to build functional pipelines too:

```js
const process =
        pipe(
            parseAsync,
            mapAsync.with((v) => ({...v, total: v.units * v.price})),
            stringifyAsync,
            compressAsync        
        )
```

Here is a dummy routine that parses some JSON, works out a total value of items, stores it back in JSON, and compresses it.

We can then call this pipeline with our data:

```js
   const compressedData = await process(inputJSON)
```

The `pipe` function creates an asynchronous process that, in conjunction with the standard [js-coroutines](http://js-coroutines.com), runs all of the jobs collaboratively on the main thread, ensuring that there is enough time for animations and interaction.

We can also just insert our own calculations that we'd like to split up:

```js
      const process = pipe(
             parseAsync,
             function * (data) {
                let i = 0
                let output = []
                for(let item of data) {
                    output.push({...item, 
                       total: item.units * item.price,
                       score: complexScore(item)
                    })
                    if((i++ % 100)==0) yield
                }
                return output
             },
             tap(console.log),
             stringifyAsync
         )         
```

Here we put a generator function into the pipeline and make sure we call `yield` now and again.  This yield call will check that we have enough time to continue or will schedule the resumption of the function on the next idle.

## New functions

<table>
<thead>
<tr>
<th>Function</th><th>Parameters</th><th>Purpose</th></tr></thead>
<tbody>
<tr>
<td><code>pipe</code></td>
<td><code>...function</code><p>each function can be an async function, a normal function or a generator</p>
<p>A function takes the current value of the pipeline and processes it.  You can use the <code>call()</code> function to pass other parameters - for instance the mapping function of a <code>mapAsync</code>.  All xxxAsync functions in js-coroutines have a <code>.with()</code> function you can use to shortcut importing call - it has the same effect.
</td>
<td> Creates an async function to execute the pipeline</td>
</tr>
<tr>
<td><code>tap</code></td>
<td><code>function(current){...}</code></td>
<td>This function adds a function to the pipeline that receives the current value, but does not return it's result.  You can use it to cause side effects like logging or saving.  The pipeline pauses execution until the function is complete.</td></tr>
<tr><td><code>branch</code></td>
<td><code>function(current){...}</code></td>
<td>This function adds a function to the pipeline that receives the current value.  You can use it to cause side effects like logging or saving.  The pipeline DOES NOT pause execution, so a new continuation is formed from this point forwards.</td></tr>
<tr>
<td><code>repeat</code></td>
<td><code>function</code>,<code>times</code></td>
<td>Creates a function that executes the specified function a number of times</td></tr>
<tr><td><code>call</code></td>
<td><code>function</code>,<code>...params</code></td>
<td>This function enables calling another function that will take the current value of the pipeline but needs extra parameters.  The parameters supplied will be appended to the current value of the pipeline.</td></tr>

</tbody>
</table>

## Demo

{% codesandbox i4q37 %}