jsBind

Tuesday, April 23, 2013

This release adds support for Internet Explorer browsers from version 6 up to version 10. There are also improvements for Firefox and Safari. In addition there are the usual performance enhancements and general code cleanups to make things nicer.

jsBind now works in all popular browsers (in no particular order):

Chrome

Firefox

Safari

Opera

IE 6, 7, 8, 9, 10

If your browser not in the list and there is there something that does not work then please let me know by submitting an issue in the issue tracker.

Tuesday, April 9, 2013

This is the third in a series of posts about how jsBind works. If you have not already done so you should read parts zero and one first.

We have seen in the previous post how the parser constructs an expression tree and we quickly mentioned that the tree is executed from the bottom up. In this post we will examine further how the expression tree is evaluated and then look at how the tree is re-evaluated when an observable object notifies that a change has occurred.

Expressions are used in two ways. When a new binding is first created the expression must be evaluated once to determine how to initially display the UI. The binding is then monitored for changes and partially re-evaluated as necessary to update the UI as the program runs. To perform the initial evaluation the expression is parsed into the expression tree and the evaluate method on the root of the tree is invoked. This method calls invoke on its child expressions and then performs whatever action is needed on the values the child expressions return before then returning its own evaluated value. So although the sequence of execution starts at the top of the tree the path of the execution immediately recursively descends to the leaf of the tree and then evaluates upwards from there. Each expression object keeps a copy of the resulting value for later.

The diagram below shows the example expression from the previous article annotated to show how the expression is evaluated and the cached values in each expression:

As this initial evaluation occurs the expressions may encounter a value that is an observable object. When this happens the expression adds a notification handler to the observable object. This allows the expression to be notified when a model value changes.

In the example above we will say that the data context ($d) is an observable object so the VariableReferenceExpression will return the data context when it is initially evaluated and the DereferenceExpression will see that this value is observable and will add a notification handler to the this object. When the model notifies that the value has changed the notification handler will be called and the DereferenceExpression will re-evaluate its value by calling the val member of the data context again. If the new value is the same as the previous value the execution will stop, if it isn't the DereferenceExpression will call its parent expression with the new value.

This will cause the BinaryOperatorExpression to subtract the new value of the right hand DereferenceExpression from the value that was previously returned from the left hand BinaryOperatorExpression and return the new value to its parent. This will then cause the UI to be updated.

Note how at every step the expressions hold copies of the previous values and they will only re-evaluate when something changes and will use the cached copies as much as possible to re-evaluate changes. This ensures that the minimum amount of work has to be done when a change occurs and also ensures that the model is not hit with a cascade of calls when a single value changes.

That was quite complicated - How about another diagram. This shows the execution path when the model notifies that the value has changed.

As you can see when the model notifies that the val property has changed all that happens is the DereferenceExpression reads in the new value and then passes it up to the BinaryOperatorExpression that then re-adds the new value to the cached value from the left hand side of the expression and then passes the new value up to the UI. This avoids the need to re-calculate all of the rest of the expression.

Thursday, April 4, 2013

This is the second in a series of posts about how jsBind works. If you have not already done so you should read part zero first where I cover the background about how observable objects work.

In this part we are going to explore how the expression parser works. The expression parser reads the binding strings defined in the data-jsBind HTML attributes and converts them into an expression tree so they can be evaluated. The binding strings are a strict subset of the JavaScript language so therefore the parser is implemented as a simplified recursive descent LR JavaScript parser. If that last bit made no sense at all don't worry I’m going to explain as we go, however if you have never read about how parsers work you might like to find out some background. I suggest you read Compilers And Compiler Generators by P. D. Terry. The original edition is now out of print so the author has published the whole book online. Another good book is Compilers, Principles, Techniques and Tools by Aho, Sethi and Ullman. This is otherwise known as the ‘red dragon book’ because of the picture of the red dragon on its cover. This is more theoretical than the first book so I suggest the first if you prefer to read code examples and the second if math works for you.

The parser is split into two parts. The first part called the tokenizer splits the string into pieces called tokens. Each token is equivalent to a word in a spoken language. The tokens are the numbers, literal strings, function names, language keywords, and the punctuation symbols that make up the expression. The tokenizer also takes care of skipping white space and new line characters etc.

The tokenizer is implemented in the getToken function of the Binder object. It uses a number of other functions for tokenizing numbers, strings and keywords etc.

The result of the tokenizer is a sequence of Token objects containing an indication of the kind of token and the value of the token. For example the tokenization of the following expression produces a list of tokens as shown:

“6 * 9 - $d.val”

Category

Value

LiteralNumber

6

Operator

“*”

LiteralNumber

9

Operator

“-”

Identifier

“$d”

Punctuation

“.”

Identifier

“val”

Once tokenized the expression is converted into an expression tree. This done by examining the string one token at a time from the left to the right (this is the LR bit of the parser). As each token is examined the parser either descends into a function that will handle that part of the language grammar or it will consume the token and return an expression object that represents the tokens parsed so far (this is the recursive descent bit). The sequence of function calls starts in the parseExpression function and from there uses all the functions that are prefixed with the name ‘parse’. These functions work to return a tree of Expression objects. There are nine expression object types, each handling a different kind of expression and most of them hold references to other expression objects to form the expression tree.

I mentioned the language grammar in parsing without explaining what it was. The grammar is the definition of what makes a valid sentence in the language. It forms a set of rules that ensure that for example a function call has commas that separate the parameters and that the parameters are enclosed in brackets or it defines that a number must be followed by an operator and another variable or a number. In the jsBind parser the grammar rules are encoded in the structure of the parser itself.

If we pass the token sequence from the previous example through the parser we get a tree structure of expression objects as follows:

Notice how the grammar rules have ensured that the operator precedence between the multiply and subtract operators have been applied to that the subtract is at the top of the tree and the multiplies are below. This will become more evident in the next post when we examine how expressions are evaluated but for now is good to know that the expressions are evaluated bottom up with the multiply happening first and the subtraction happening second.

Sunday, March 31, 2013

This is the first of a few posts about how jsBind works. I’m sure that knowing how jsBind works under the hood will make it much easier to work with and knowing how an API library works and what it does internally makes it much easier to get the most out of it.

jsBind uses a few different techniques to achieve its end. It is part language parser, part interpreter, part event manager and part API library. In part one I will start by describing how jsBind parses the binding expressions into an expression tree and I will continue in future posts to describe how expressions are evaluated and how they are re-evaluated when the underlying data is changed. First though we need to cover some background about how observable objects work so we can see how these interact with expression tree later.

Observable objects are based on the gang of four design pattern called the Observer Pattern (if you have not seen this before go take a quick look, its well worth a read as these design patterns are useful in many situations). An observable object is an object that tells one or more other objects when something happens to it. In our case we tell other objects by invoking callbacks whenever data held in our observable object changes.

For jsBind to recognize an object as being observable it must implement two methods. These are:

addObserverremoveObserver

The functions are quite straightforward, an observable object contains an internal list of methods to call when data changes and these methods manipulate that list. The first adds a method to the internal list and the second removes a method. It is up to the implementation of the observable object to decide how the list is maintained. jsBind objects just use a straightforward array with a couple of lines of extra code to lazily allocate the array when it is first needed and to delete the array as soon as its empty.

When the observable object wants to notify its observers it iterates through its internal list of methods and invokes each method with the data. The handling method is expected have one parameter that takes the name of the member that has changed. jsBind observable objects implement this in the notify method.

jsBind supplies several objects that implement this Observer design pattern so most of the time you do not have to roll your own unless you really want to. These objects are:

The first one of these is a base class that provides the mechanism to add, remove, and notify subscribers. The next four use this base class for storing a single value of different types and to raise a notification every time the value is changed. The ObservableString, Number and Bool objects are all type specific versions of the ObservableValue object and are really of most use for TypeScript projects where type checking is provided.

The ObservableCollection object is a bit more of a special case of the Observer pattern that allows for several optimizations used by jsBind to make the processing of anything that is based on a list of items much more efficient. Collections are mostly used with ForEach bindings to generate a list of UI elements. We want to avoid re-generating the entire list in the UI when just one element of the collection changes or is added or removed. To achieve this we extend the Observer pattern so that we can pass more information to the observer to indicate which items were changed and how they changed. This then allows the ForEach binding to work more efficiently by only changing the minimum amount of the UI to properly reflect the changes in the underlying data.

ObservableCollection uses the same addObserver and removeObserver methods as before except that this time they are called addCollectionObserver and removeCollectionObserver and they expect to be give a more complicated notification method to call:

This method expects to be called with three lists and three numbers in pairs. These provide a list of items that have been added and the index at which the adding started, a list of the items that have been replaced (updated) and the index at which this started, and a final list of items that have been deleted and the index at which this started. The indexes are all based on the position in the array before any changes were made.

Of course not all operations on a collection would cause items to be added, updated, and deleted all at the same time. To handle this situation the unused arguments are passed an empty array and an index of -1.

That covers things as far as all the background on observable objects goes. It is worth noting that although jsBind provides these objects for you to use in your model code there is nothing to stop you from implementing your own observable objects directly within your model. If you have a model with lots of members that you need to bind you can either wrap each value in an ObservableValue or you can directly implement the observer pattern and notify the name of the member that changes. You can use the Observable object and derive from it in your own model or for TypeScript programs you can also implement the IObservable and IObservableCollection interfaces. The Clock example is a good demonstration of this. It extends the Observable base object and notifies the same set of observers whenever the hours, minutes, or seconds members change.

That's all for now. In the next post we will look at the expression parser. In the meantime you can find all the source code for jsBind on GitHub and more information on the jsBind web site.

Sunday, March 10, 2013

Announcing jsBind v1.0.1 release. This is a maintenance release that addresses bugs in the 1.0.0 release. In addition to adding a significant unit test coverage there have been fixes for the following:

Problems with the way that template bindings were handled.

ForEach and Template bindings conflicting if the ForEach binding was specified first.

Bugs with handling arrays in binding expressions.

In addition to the above fixes there have also been several performance enhancements and general code cleanups to make things nicer.

Wednesday, February 20, 2013

Welcome to the new jsBind blog. This is where announcements about new releases, examples, documentation and future development plans will me made. Check back soon for more. In the mean time you can find out more about jsBind at js-bind.com.