Introduction
DB.js is a tiny (5.8K minimized) MVVM library written by Oleg Shalaev.
DB.js is a tiny (5.8K minimized) MVVM library written by Oleg Shalaev.
It also stands for "easy", "fast", "flexible", and "reliable".
Consider a simple probabilistic problem: there is a machine (or a car, airplane, space ship, software) composed of many parts (or lines of code), each part having small probability to fail. How does the probability to have no failures in the machine scale with the number of parts?
It decreases exponentially: a device built of 3.000 parts will be more reliable (and easier to fix) than the one built using 30.000 parts, even if parts of the latter have (say, twice) better quality. High quality of every single part is suppressed by the overall complexity of the device.
The size of frameworks at the bottom of this table seems unreasonable: were the creators paid per kilobyte of code?
Framework | Size (K) |
---|---|
DB.js | 5.8 |
Preact 7.2.0 | 16 |
Inferno 1.2.2 | 48 |
Vue 2.4.2 | 58.8 |
KnockoutJS | 68 |
React 16.2.0 + React DOM | 97.5 |
React 0.14.5 + React DOM | 133 |
React 0.14.5 + React DOM + Redux | 139 |
Angular 1.4.5 | 143 |
Angular 1.5.6 | 156 |
Ember 2.2.0 | 435 |
Ember 1.13.8 | 486 |
Angular 2 | 566 |
Angular 2 + Rx | 766 |
With the general probabilistic consideration above one does not have to try every other MVVM in order to conclude that DB.js is less buggy and more versatile than most other MVVMs.
Being dependent on someone else's large code is bad because its complexity means that you cannot fix the errors and optimize the code for your needs.
Web developers already have hard time being dependent on creators of Firefox, Safari, and Chrome. I do not like certain things in Firefox but I realize that I will never have time to fix them. Fortunately there is no monopoly for now: if Mozilla becomes too awful, people can easily escape to Chrome and vice versa.
But for businesses relying upon React or Angular it would be hard to switch: they become dependent on Facebook or Google – huge companies with lots of power and unclear intentions.
DB.js was inspired by KnockoutJS, so their syntax is similar.
Observable is an object created by DB.observable
, for example,
var spanText=new DB.observable([],{type:'str',value:"ku-ku"});
creates an observable spanText
having string value and sets its value to "ku-ku".
Any observable is a function:
spanText()
,spanText("bu-bu")
.DB.scanHTML()
is called (inside HTML or from another JS-file). It scans all nodes for the DB.js-related properties. For example, if it encounters <span db="text:spanText"></span>
, the text content (more precisely, textContent) of this span-node will be bound to the value of the observable spanText
.spanText
by calling spanText("bu-bu")
, the corresponding span element will be automatically changed from the initial value "ku-ku" to "bu-bu".Note: If you create DOM-elements (DOMs) dynamically after you have already called DB.scanHTML()
at startup, call it again for these new DOMs. With no arguments, DB.scanHTML()
scans the entire HTML. One can limit the scan to certain DOMs and their children: DB.scanHTML([DOM1,DOM2,…])
.
An observable may depend on other observables. For example, consider the following definition:
var husbandWeight=new DB.observable([],{type:'int',value:220}), wifeWeight=new DB.observable([],{type:'int',value:160}), coupleWeight=new DB.observable([husbandWeight,wifeWeight], {type:'int', compute:()=>husbandWeight()+wifeWeight()});
where type:'int'
specifies the (integer) value type, and value:220
together with value:160
assigns the initial values.
The first two observables, husbandWeight
and wifeWeight
do not depend on any other observable.
The third observable, coupleWeight
is declared to be dependent on both husbandWeight
and wifeWeight
. Conversely, the value of coupleWeight
will be re-calculated every time husbandWeight
or wifeWeight
is updated. (The function specified in compute
field will be used for that.)
With these observables, the following piece of HTML code will always be up to date:
Now the husband weights <span db="text:husbandWeight"></span> pounds, and his wife weights <span db="text:wifeWeight"></span> pounds, so their total weight is <span db="text:coupleWeight"></span> pounds.
where text
is the binding type connecting observable values to textContent of the corresponding span elements.
Suppose that during the dinner the husband gained 2 pounds, and the wife gained one. In order to update the HTML with their new weight, we execute
husbandWeight(2+husbandWeight()); wifeWeight(1+wifeWeight());
After that, the value of coupleWeight
together with all HTML elements bound to our observables husbandWeight
, wifeWeight
, and coupleWeight
, will be automatically updated.
In the above example we saw how text
binding works. Other binding names:
This list of bindings is complete and sufficient even for most sophisticated web pages.
Due to its size, DB.js can be easily extended by whoever wants to use it. This flexibility is the main advantage of brevity; better performance (faster web pages) is just an extra benefit.
Although DB.js is small, its code is non-trivial. The following web pages ensure that it is not damaged during the latest update:
These web pages should work properly in modern (3 years old) versions of Firefox, Chrome, and Safari.
Object.defineProperty(window, 'myObservable', {get:()=>123})