Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
reactive-function
Advanced tools
A library for managing reactive data flows.
This library provides the ability to define reactive data flows by modeling application state as a directed graph and using topological sorting to compute the order in which changes should be propagated.
This library is built on top of reactive-property and graph-data-structure.
Table of Contents
Suppose you have two reactive properties to represent someone's first and last name.
var firstName = ReactiveProperty("Jane");
var lastName = ReactiveProperty("Smith");
Another reactive property can represent the full name of the person.
var fullName = ReactiveProperty();
You could set the full name value like this.
fullName(firstName() + " " + lastName());
However, the above code sets the value of fullName
only once. Here's how you can define a ReactiveFunction that automatically updates fullName
whenever firstName
or lastName
change.
var reactiveFunction = ReactiveFunction({
inputs: [firstName, lastName],
output: fullName,
callback: function (first, last){
return first + " " + last;
}
});
The data flow graph for the example code above.
Whenever firstName
or lastName
change, the callback defined above will be executed on the next animation frame. If you don't want to wait until the next animation frame, you can force a synchronous evaluation of the data flow graph by invoking digest.
ReactiveFunction.digest();
Now you can access the computed fullName
value by invoking it as a getter.
console.log(fullName()); // Prints "Jane Smith"
The output of one reactive function can be used as an input to another.
Here, b is both an output and an input.
var a = ReactiveProperty(5);
var b = ReactiveProperty();
var c = ReactiveProperty();
ReactiveFunction({
inputs: [a],
output: b,
callback: function (a){ return a * 2; }
});
ReactiveFunction({
inputs: [b],
output: c,
callback: function (b){ return b / 2; }
});
ReactiveFunction.digest();
assert.equal(c(), 5);
This is the case where Model.js fails because it uses Breadth-first Search to propagate changes. In this graph, propagation using breadth-first search would cause e
to be set twice, and the first time it would be set with an inconsistent state. This fundamental flaw cropped up as flashes of inconstistent states in some interactive visualizations built on Model.js. For example, it happens when you change the X column in this Magic Heat Map. This flaw in Model.js is the main inspiration for making this library and using topological sort, which is the correct algorithm for propagating data flows and avoiding inconsistent states.
The tricky case, where breadth-first propagation fails.
var a = ReactiveProperty(5);
var b = ReactiveProperty();
var c = ReactiveProperty();
var d = ReactiveProperty();
var e = ReactiveProperty();
ReactiveFunction({ inputs: [a], output: b, callback: function (a){ return a * 2; } });
ReactiveFunction({ inputs: [b], output: c, callback: function (b){ return b + 5; } });
ReactiveFunction({ inputs: [a], output: d, callback: function (a){ return a * 3; } });
ReactiveFunction({ inputs: [c, d], output: e, callback: function (c, d){ return c + d; } });
ReactiveFunction.digest();
assert.equal(e(), ((a() * 2) + 5) + (a() * 3));
a(10);
ReactiveFunction.digest();
assert.equal(e(), ((a() * 2) + 5) + (a() * 3));
Ohm's Law is a mathematical relationship between 3 quantities in electrical circuits:
Given any two of these values, one can calculate the third. Here's an example where if any two of the values are set, the third will automatically be calculated.
The data flow graph for Ohm's Law.
var I = ReactiveProperty();
var V = ReactiveProperty();
var R = ReactiveProperty();
ReactiveFunction({ output: V, inputs: [I, R], callback: function (i, r){ return i * r; } });
ReactiveFunction({ output: I, inputs: [V, R], callback: function (v, r){ return v / r; } });
ReactiveFunction({ output: R, inputs: [V, I], callback: function (v, i){ return v / i; } });
V(9)
I(2)
ReactiveFunction.digest();
console.log(R()); // Prints 4.5
R(6)
I(2)
ReactiveFunction.digest();
console.log(V()); // Prints 12
V(9);
R(18);
ReactiveFunction.digest();
console.log(I()); // Prints 0.5
For more detailed example code, have a look at the tests.
If you are using NPM, install this package with:
npm install reactive-function
Require it in your code like this:
var ReactiveFunction = require("reactive-function");
This library is designed to work with reactive-property, you'll need that too.
npm install reactive-property
var ReactiveProperty = require("reactive-property");
# ReactiveFunction(options)
Construct a new reactive function. The options argument should have the following properties.
This constructor sets up a reactive function such that callback be invoked
An input property is considered "defined" if it has any value other than undefined
. The special value null
is considered to be defined.
An input property is considered "changed" when
Input properties for one reactive function may also be outputs of another.
# reactiveFunction.destroy()
Cleans up resources allocated to this reactive function.
More specifically:
You should invoke this function when finished using reactive functions in order to avoid memory leaks.
# ReactiveFunction.link(propertyA, propertyB)
Sets up one-way data binding from propertyA to propertyB. Returns an instance of ReactiveFunction.
Arguments:
Example:
var a = ReactiveProperty(5);
var b = ReactiveProperty(10);
var link = ReactiveFunction.link(a, b);
This is equivalent to:
var a = ReactiveProperty(5);
var b = ReactiveProperty(10);
var link = ReactiveFunction({
inputs: [a],
output: b,
callback: function (a){ return a; }
});
# ReactiveFunction.digest()
Propagates changes from input properties through the data flow graph defined by all reactive properties using topological sorting. An edge in the data flow graph corresponds to a case where the output of one reactive function is used as an input to another.
Whenever any input properties for any reactive function change, digest is debounced (scheduled for invocation) on the nextFrame. Because it is debounced, multiple synchronous changes to input properties collapse into a single digest invocation.
Digests are debounced to the next animation frame rather than the next tick because browsers will render the page at most every animation frame (approximately 60 frames per second). This means that if DOM manipulations are triggered by reactive functions, and input properties are changed more frequently than 60 times per second (e.g. mouse or keyboard events), the DOM manipulations will only occur at most 60 times per second, not more than that.
# ReactiveFunction.nextFrame(callback)
Schedules the given function to execute on the next animation frame or next tick.
This is a simple polyfill for requestAnimationFrame that falls back to setTimeout. The main reason for having this is for use in the tests, which run in a Node.js environment where requestAnimationFrame
is not available. Automatic digests are debounced against this function.
# ReactiveFunction.serializeGraph()
Serializes the data flow graph. Returns an object with the following properties.
nodes
An array of objects, each with the following properties.
id
The node identifier string.propertyName
The property name for this node, derived from property.propertyName
for each property.links
An array of objects representing edges, each with the following properties.
source
The node identifier string of the source node (u).target
The node identifier string of the target node (v).Example:
var firstName = ReactiveProperty("Jane");
var lastName = ReactiveProperty("Smith");
var fullName = ReactiveProperty();
// For serialization.
firstName.propertyName = "firstName";
lastName.propertyName = "lastName";
fullName.propertyName = "fullName";
ReactiveFunction({
inputs: [firstName, lastName],
output: fullName,
callback: function (first, last){
return first + " " + last;
}
});
var serialized = ReactiveFunction.serializeGraph();
The value of serialized
will be:
{
"nodes": [
{ "id": "95", "propertyName": "fullName" },
{ "id": "96", "propertyName": "firstName" },
{ "id": "97", "propertyName": "lastName" }
],
"links": [
{ "source": "96", "target": "95" },
{ "source": "97", "target": "95" }
]
}
See also:
FAQs
A library for managing data flows and changing state.
The npm package reactive-function receives a total of 4 weekly downloads. As such, reactive-function popularity was classified as not popular.
We found that reactive-function demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.