Expr
expr() allows you turn a function into an
agent:
/*!*/import { wrap, map, expr, group } from '@connectv/core';
import { fromEvent } from 'rxjs';
let a = document.getElementById('a') as HTMLInputElement;
let b = document.getElementById('b') as HTMLInputElement;
let p = document.getElementById('p');
group(
wrap(fromEvent(a, 'input')).to(map(() => parseInt(a.value))), //--> get the value of 'a'
wrap(fromEvent(b, 'input')).to(map(() => parseInt(b.value))), //--> get the value of 'b'
)
/*!*/.serialTo(expr((a, b) => a + b)) //--> add them
.subscribe(v => p.innerHTML = v); //--> display the result
expr()s support
implicit connection,
as evident from the example above.
In this example, if you wanted to do the same thing explicitly, it would look like this:
let e = expr((a, b) => a + b);
group(...).serialTo(e.in(0), e.in(1));
e.result.subscribe(...); //--> `e.result` is short-hand for `e.out('result')`
Async functions
You can run async operations in an
expr() by returning a function as return value:
/*!*/import { source, sink, expr, group } from '@connectv/core';
let a = source();
let b = source();
group(a, b)
/*!*/.serialTo(expr((msg, delay) =>
/*!*/ done => {
/*!*/ setTimeout(() => done(`(after ${delay}ms): ${msg}`), delay);
/*!*/ })
)
.subscribe(console.log);
a.send('hellow'); b.send(100); //> `(after 100ms): hellow`
a.send('world'); //> `(after 100ms): world`
b.send(1000); //> `(after 1000ms): world`
Control
You can control when the function is executed using its
.control property:
import { wrap, map, expr, group } from '@connectv/core';
import { fromEvent } from 'rxjs';
let a = document.getElementById('a') as HTMLInputElement;
let b = document.getElementById('b') as HTMLInputElement;
let btn = document.getElementById('btn');
let p = document.getElementById('p');
let e = expr((a, b) => a + b);
/*!*/wrap(fromEvent(btn, 'click')) //--> wait for the click before
/*!*/ .to(e.control); //... running the function
group(
wrap(fromEvent(a, 'input')).to(map(() => parseInt(a.value))),
wrap(fromEvent(b, 'input')).to(map(() => parseInt(b.value))),
).serialTo(e)
.subscribe(v => p.innerHTML = v);
Note that the
expr() waits for its control signal for every execution.
Error handling
Similar to
map(), synchronous errors happening during
execution of the function are handled automatically. For async errors, the returned function
is similarly provided with an error callback as its second argument. You should catch possible errors
and pass them to this callback:
import { expr } from '@connectv/core';
//--> sync error handling in expr:
let e = expr(() => {
/*!*/ throw new Error('because why not');
});
e.result.subscribe(
() => console.log('not here ...'), //--> normal callback
/*!*/ () => console.log('E HAD ERROR!') //--> error callback
);
//--> async error handling in expr:
/*!*/let brokenPromise = () => new Promise(() => { throw new Error('well ...')});
/*!*/let f = expr(() => (done, error) => {
setImmediate(() =>
/*!*/ brokenPromise().catch(error)); //--> passing the caught error on ...
});
f.result.subscribe(
() => console.log('not here too ...'), //--> normal callback
/*!*/ () => console.log('F HAD ERROR!') //--> error callback
)
Signature
An
expr() will have one input pin for each input of your function, named numerically:
let e = expr((a, b, c) => {
// ...
});
e.in(0); //--> this pin's data goes to param a
e.in(1); //--> this pin's data goes to param b
e.in(2); //--> this pin's data goes to param c
Each
expr() also has a
"result" output, which will relay the return value
of the function:
e.out('result') //--> this will get you the return value
e.result //--> this is a shortcut for the same thing
Further reading