EN | KR
FxJS - Functional Extensions for Javascript
FxJS is a functional Javascript library based on Iterable / Iterator, Generator, and Promise in ECMAScript 6.
Getting Started
Installation
In the browser environment
- Modern Browser (>= 2% and last 2 versions)
<script src="https://unpkg.com/fxjs/dist/fx.js"></script>
- Legacy Browser (IE11)
<script src="https://unpkg.com/fxjs/dist/fx.es5.js"></script>
- Usage
<script>
const { L, C } = window._;
_.go(
[1, 2, 3],
L.map(a => a * a),
L.map(_.delay(300)),
C.takeAll,
_.reduce(_.add),
console.log
);
</script>
Note: When the browser loads the fx.js
script file, _
is used as a global variable.
In the node.js environment
FxJS is a Dual Module Package that supports both CommonJS and ES6 Module.
Among the two module types of the fxjs package, commonjs support node.js v6
or higher, and ESM is available from node.js v12
or higher.
npm install fxjs
-
CommonJS (>= node v6)
const FxJS = require("fxjs");
const _ = require("fxjs/Strict");
const L = require("fxjs/Lazy");
const C = require("fxjs/Concurrency");
const { reduce, mapL, takeAllC } = FxJS;
const rangeL = require("fxjs/Lazy/rangeL");
_.go(
rangeL(1, 4),
L.map(a => a * a),
L.map(_.delay(300)),
C.takeAll,
_.reduce(_.add),
console.log
);
-
ES6 Module (>= node v12)
import { add, delay, go, reduce, rangeL } from "fxjs";
import * as L from "fxjs/Lazy";
import * as C from "fxjs/Concurrency";
go(
rangeL(1, 4),
L.map(a => a * a),
L.map(delay(300)),
C.takeAll,
reduce(add),
console.log
);
Dual Package Hazard
FxJS adopted the Isolate state approach in two ways to support the Dual Module Package, which was introduced in the official Node.js document.
Therefore, when using both CommonJS and ES modules, care must be taken to compare the equivalence of modules or function objects as shown below. For more information, see Node.js Document.
import { createRequire } from "module";
import * as fxjs_mjs from "fxjs";
import go_mjs from "fxjs/Strict/go.js";
const require = createRequire(import.meta.url);
const fxjs_cjs = require('fxjs');
const go_cjs = require('fxjs/Strict/go');
console.log(fxjs_mjs === fxjs_cjs);
console.log(go_mjs === go_cjs);
console.log(fxjs_cjs.go === go_cjs);
console.log(fxjs_mjs.go === go_mjs);
Iteration protocols
You can evaluate the iterator as a function of FxJS.
function* fibonacci() {
let a = 0,
b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const f = pipe(
fibonacci,
L.filter((n) => n % 2 == 0),
L.takeWhile((n) => n < 10)
);
const iterator = f();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
reduce((a, b) => a + b, f());
Iterable programming
Any value can be used with FxJS if it has a [Symbol.iterator]()
method.
const res = go(
[1, 2, 3, 4, 5],
filter((a) => a % 2),
reduce(add)
);
log(res);
Lazy evaluation
You can do 'lazy evaluation' as a function of the L
namespace.
const res = go(
L.range(Infinity),
L.filter((a) => a % 2),
L.take(3),
reduce(add)
);
log(res);
FRP style
Functional reactive programming style.
go(
L.range(Infinity),
L.map(delay(1000)),
L.map((a) => a + 10),
L.take(3),
each(log)
);
Promise/async/await
Asynchronous control is easy.
await go(
L.interval(1000),
L.map((a) => a + 30),
L.takeUntil((a) => a == 33),
each(log)
);
const res = await go(
L.interval(1000),
L.map((a) => a + 20),
L.takeWhile((a) => a < 23),
L.map(tap(log)),
reduce(add)
);
log(res);
Concurrency
C
functions can be evaluated concurrency.
await map(getPage, range(1, 5));
const pages = await C.map(getPage, range(1, 5));
Like Clojure Reducers, you can handle concurrency.
go(
range(1, 5),
map(getPage),
filter((page) => page.line > 50),
map(getWords),
flat,
countBy(identity),
log
);
go(
L.range(1, 5),
L.map(getPage),
L.filter((page) => page.line > 50),
L.map(getWords),
C.takeAll,
flat,
countBy(identity),
log
);
go(
L.range(1, 5),
L.map(getPage),
L.filter((page) => page.line > 50),
L.map(getWords),
C.takeAll(2),
flat,
countBy(identity),
log
);
Error handling
You can use JavaScript standard error handling.
const b = go(
0,
(a) => a + 1,
(a) => a + 10,
(a) => a + 100
);
console.log(b);
try {
const b = go(
0,
(a) => {
throw { hi: "ho" };
},
(a) => a + 10,
(a) => a + 100
);
console.log(b);
} catch (c) {
console.log(c);
}
You can use async/await and try/catch to handle asynchronous error handling.
const b = await go(
0,
(a) => Promise.resolve(a + 1),
(a) => a + 10,
(a) => a + 100
);
console.log(b);
try {
const b = await go(
0,
(a) => Promise.resolve(a + 1),
(a) => Promise.reject({ hi: "ho" }),
(a) => a + 100
);
console.log(b);
} catch (c) {
console.log(c);
}
API
Extension Libraries
The above libraries are based on FxJS.
FxSQL and FxDOM are libraries that can handle SQL and DOM through functional APIs,respectively.