Bacon.js
Functional reactive programming library for TypeScript and JavaScript
Install / Use
/learn @baconjs/Bacon.jsREADME
Bacon.js
<img src="https://raw.github.com/baconjs/bacon.js/master/logo.png" align="right" width="300px" />A functional reactive programming lib for TypeScript JavaScript, written in TypeScript.
Turns your event spaghetti into clean and declarative feng shui bacon, by switching
from imperative to functional. It's like replacing nested for-loops with functional programming
concepts like map and filter. Stop working on individual events and work with event streams instead.
Combine your data with merge and combine.
Then switch to the heavier weapons and wield flatMap and combineTemplate like a boss.
Here's the stuff.
- API docs
- Homepage
- Source files
- Generated javascript
- Specs
- Examples
- Wiki with more docs, related projects and more
- Gitter chat for developers of Bacon.
- Migrating to 2.0
Install and Usage
Typescript
Bacon.js starting from version 3.0 is a Typescript library so you won't need any external types. Just
Install using npm.
npm install baconjs
Then you can
import { EventStream, once } from "baconjs"
let s: EventStream<string> = once("hello")
s.log()
As you can see, the global methods, such as once are imported separately.
Check out the new API Documentation, that's now generated using Typedoc from the Typescript source code.
Modern ES6 Browser, Node.js v.12+
You can directly import Bacon.js as single aggregated ES6 module.
import * as Bacon from 'node_modules/baconjs/dist/Bacon.mjs';
Bacon.once("hello").log();
NPM, CommonJS, Node.js
If you're on to CommonJS (node.js, webpack or similar) you can install Bacon using npm.
npm install baconjs
Try it like this:
node
Bacon=require("baconjs")
Bacon.once("hello").log()
The global methods, such as once are available in the Bacon object.
Bower
For bower users:
bower install bacon
CDN / Script Tags
Both minified and unminified versions available on cdnjs.
So you can also include Bacon.js using
<script src="https://cdnjs.cloudflare.com/ajax/libs/bacon.js/2.0.9/Bacon.js"></script>
<script>
Bacon.once("hello").log()
</script>
AMD / require.js
Bacon.js is an UMD module so it should work with AMD/require.js too. Not tested lately though.
Github
Prefer to drink from the firehose? Download from Github master.
Intro
The idea of Functional Reactive Programming is quite well described by Conal Elliot at Stack Overflow.
Bacon.js is a library for functional reactive programming. Or let's say it's a library for working with events in EventStreams and dynamic values (which are called Properties in Bacon.js).
You can wrap an event source, say "mouse clicks on a DOM element" into an EventStream by saying
let $ = (selector) => document.querySelector(selector)
var clickE = Bacon.fromEvent($("h1"), "click")
The $ helper function above could be replaced with, for instance, jQuery or Zepto.
Each EventStream represents a stream of events. It is an Observable, meaning
that you can listen to events in the stream using, for instance, the onValue method
with a callback. Like this:
clickE.onValue(() => alert("you clicked the h1 element") )
But you can do neater stuff too. The Bacon of Bacon.js is that you can transform,
filter and combine these streams in a multitude of ways (see EventStream API). The methods map,
filter, for example, are similar to same functions in functional list programming
(like Underscore). So, if you say
let plusE = Bacon.fromEvent($("#plus"), "click").map(1)
let minusE = Bacon.fromEvent($("#minus"), "click").map(-1)
let bothE = plusE.merge(minusE)
.. you'll have a stream that will output the number 1 when the "plus" button is clicked
and another stream outputting -1 when the "minus" button is clicked. The bothE stream will
be a merged stream containing events from both the plus and minus streams. This allows
you to subscribe to both streams with one handler:
bothE.onValue(val => { /* val will be 1 or -1 */ console.log(val) })
Note that you can also use the log method to log stream values to console:
bothE.log()
In addition to EventStreams, bacon.js has a thing called Property, that is almost like an
EventStream, but has a "current value". So things that change and have a current state are
Properties, while things that consist of discrete events are EventStreams. You could think
mouse clicks as an EventStream and mouse cursor position as a Property. You can create Properties from
an EventStream with scan or toProperty methods. So, let's say
let add = (x, y) => x + y
let counterP = bothE.scan(0, add)
counterP.onValue(sum => $("#sum").textContent = sum )
The counterP property will contain the sum of the values in the bothE stream, so it's practically
a counter that can be increased and decreased using the plus and minus buttons. The scan method
was used here to calculate the "current sum" of events in the bothE stream, by giving a "seed value"
0 and an "accumulator function" add. The scan method creates a property that starts with the given
seed value and on each event in the source stream applies the accumulator function to the current
property value and the new value from the stream.
Hiding and showing the result div depending on the content of the property value is equally straightforward
let hiddenIfZero = value => value == 0 ? "hidden" : "visible"
counterP.map(hiddenIfZero)
.onValue(visibility => { $("#sum").style.visibility = visibility })
For an actual (though a bit outdated) tutorial, please check out my blog posts
API
Creating EventStreams and Properties
There's a multitude of methods for creating an EventStream from different sources, including the DOM, node callbacks and promises for example. See EventStream documentation.
Properties are usually created based on EventStreams. Some common ways are introduced in Property documentation.
Combining multiple streams and properties
You can combine the latest value from multple sources using combine, combineAsArray, combineWith or combineTemplate.
You can merge multiple streams into one using merge or mergeAll.
You can concat streams using [concat](http://baconjs.github.io/api3/classes/observable.html#c
Related Skills
node-connect
337.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.1kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
337.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.1kCommit, push, and open a PR
