Your library should not break-down as your application and organization grow and technologies change. CanJS’s flexibility will keep it valuable to you far into the future.
Supports multiple libraries and frameworks
Want to share code between a Zepto mobile app and a jQuery desktop app? No problem. CanJS code (especially models) can be shared across libraries, and so can skill sets! Working on a Dojo project today and a YUI one tomorrow? Don’t throw away all of your skills.
Designed for plugins
CanJS is extracted from JavaScriptMVC, but currently supports almost all of its MVC functionality through plugins. Start small, with its basic functionality, and extend it with plugins that handle things like:
setters
serialization / deserialization
jQuery plugin generation
validations
calling super methods
These plugins have forced the core to be quite extendable, making 3rd party plugin development easy.
Engineered limber
CanJS’s tools are designed to work under almost every situation. Your server sends back XML with strange urls? That’s ok, overwrite can.Model.findAll or can.Model.models. Want some special teardown code for a control? Overwrite can.Control:destroy.
But our favorite bit of flexibility is how can.Observe works with nested data. It converts nested objects into observes automatically. For example:
var person = new can.Observe({
name: { first: 'Justin', last: 'Meyer' },
hobbies: [ 'programming', 'party rocking' ]
})
person.attr( 'name.first' ) //-> 'Justin'
person.attr( 'hobbies.0' ) //-> 'programming'
But most important, change events bubble, letting observes listen for when a nested property changes:
Memory safety is really important, especially in long-lived, dynamic pages. CanJS combats this menace in two important and unique ways:
Controls that unbind event handlers auto-magically
Using templated event binding, Controls can listen to events on objects other than their element. For example, a tooltip listening to the window looks like:
var Tooltip = can.Control.extend({
'{window} click': function( el, ev ) {
// hide only if we clicked outside the tooltip
if (!this.element.has( ev.target ) {
this.element.remove();
}
}
})
// create a Tooltip
var tooltipElement = $( '<div>INFO</div>' ).appendTo( el )
var tooltipInstance = new Tooltip( tooltipElement );
window now has a reference to the control which keeps the tooltipInstance and everything the tooltip instance might reference in memory. CanJS overwrites each library’s element remove functionality to destroy controls. Destroying a control unbinds all of its event handlers, removing any memory leaks auto-magically.
A model store that does not leak
It’s relatively common to load the same model instance multiple times on a single page. For example, an app might request todos due today and high-priority todos and render them like:
can.Model knows that this data represents the same todo and only creates one instance. This means that a single model instance is in both lists. By changing the todo’s name or destroying it, both lists will be changed.
However, model only stores these model instances while something is binding to them. Once nothing is bound to the model instance, they are removed from the store, freeing their memory for garbage collection.
Ease of use
This site highlights the most important features of CanJS. The library comes with thorough documentation and examples on the CanJS documentation page. There are example apps for each library and several example for jQuery.
CanJS is also supported by Bitovi. We are extremely active on the forums. And should the need arise, we provide support, training, and development.
Fast
Size
On top of jQuery, CanJS is ~20KB. Here’s some other frameworks for comparison:
Backbone 8.97KB (with Underscore.js)
Angular 24KB
Knockout 13KB
Ember 37KB
Batman 15KB
Size is not everything. It really is what’s inside that counts. And that’s where we think CanJS really delivers a lot of bang for your buck.
Speed
The importance of performance is almost impossible to exaggerate. CanJS’s guts are highly optimized. See how:
This means that CanJS and Knockout are slightly faster at different things, but are likely tied for the fastest live-binding libraries.
Note: AngularJS throttles updates, which means it doesn’t fit well with these tests.
Model and view deferred support for parallel loading
Deferreds are simply awesome for handling asynchronous behavior. can.Model produces deferreds and can.view consumes them. With the view modifiers plugin, you can load a template and its data in parallel and render it into an element with:
Although can.EJS’s live-binding is super fast, setting up live data binding can be too slow in certain situations (like rendering a list of 1000 items). EJS’s live binding is opt-in. It only turns on if you are using the attr method. If the following template binds to a todo's name …
<li> <%= todo.attr('name') %> </li>
… the following doesn’t setup live-binding and renders much faster …
Flexible
Your library should not break-down as your application and organization grow and technologies change. CanJS’s flexibility will keep it valuable to you far into the future.
Supports multiple libraries and frameworks
Want to share code between a Zepto mobile app and a jQuery desktop app? No problem. CanJS code (especially models) can be shared across libraries, and so can skill sets! Working on a Dojo project today and a YUI one tomorrow? Don’t throw away all of your skills.
Designed for plugins
CanJS is extracted from JavaScriptMVC, but currently supports almost all of its MVC functionality through plugins. Start small, with its basic functionality, and extend it with plugins that handle things like:
These plugins have forced the core to be quite extendable, making 3rd party plugin development easy.
Engineered limber
CanJS’s tools are designed to work under almost every situation. Your server sends back XML with strange urls? That’s ok, overwrite can.Model.findAll or can.Model.models. Want some special teardown code for a control? Overwrite can.Control:destroy.
But our favorite bit of flexibility is how can.Observe works with nested data. It converts nested objects into observes automatically. For example:
But most important,
change
events bubble, letting observes listen for when a nested property changes:Powerful
Safety
Memory safety is really important, especially in long-lived, dynamic pages. CanJS combats this menace in two important and unique ways:
Controls that unbind event handlers auto-magically
Using templated event binding, Controls can listen to events on objects other than their element. For example, a tooltip listening to the window looks like:
window
now has a reference to the control which keeps thetooltipInstance
and everything the tooltip instance might reference in memory. CanJS overwrites each library’s element remove functionality to destroy controls. Destroying a control unbinds all of its event handlers, removing any memory leaks auto-magically.A model store that does not leak
It’s relatively common to load the same model instance multiple times on a single page. For example, an app might request todos due today and high-priority todos and render them like:
todosList.ejs
might look like:If the result for of
Todo.findAll( { due: 'today' } )
andTodo.findAll( { type: 'critical' } )
both share a todo instance like:can.Model knows that this data represents the same todo and only creates one instance. This means that a single model instance is in both lists. By changing the todo’s name or destroying it, both lists will be changed.
However, model only stores these model instances while something is binding to them. Once nothing is bound to the model instance, they are removed from the store, freeing their memory for garbage collection.
Ease of use
This site highlights the most important features of CanJS. The library comes with thorough documentation and examples on the CanJS documentation page. There are example apps for each library and several example for jQuery.
CanJS is also supported by Bitovi. We are extremely active on the forums. And should the need arise, we provide support, training, and development.
Fast
Size
On top of jQuery, CanJS is ~20KB. Here’s some other frameworks for comparison:
Size is not everything. It really is what’s inside that counts. And that’s where we think CanJS really delivers a lot of bang for your buck.
Speed
The importance of performance is almost impossible to exaggerate. CanJS’s guts are highly optimized. See how:
Control initialization
can.Control pre-processes event handlers so binding is super fast. Compare initializing a can.Control, Backbone.View and Ember.View tabs widget:
Tabs initialization performance
This makes a big difference for page initialization if your site has lots of controls.
Live binding
CanJS’s live-binding is very fast. It only updates what’s necessary when it’s necessary. Compare its template rendering performance with three other common MVC frameworks:
In this test, CanJS has the fastest live-binding. Backbone and YUI are not doing live-binding, but CanJS is still the fastest.
In the popular counting circle example, Knockout visually appears the fastest, followed by CanJS.
This means that CanJS and Knockout are slightly faster at different things, but are likely tied for the fastest live-binding libraries.
Note: AngularJS throttles updates, which means it doesn’t fit well with these tests.
Model and view deferred support for parallel loading
Deferreds are simply awesome for handling asynchronous behavior. can.Model produces deferreds and can.view consumes them. With the view modifiers plugin, you can load a template and its data in parallel and render it into an element with:
Hot. You can do this without the view modifiers plugin like:
Opt-in data binding
Although can.EJS’s live-binding is super fast, setting up live data binding can be too slow in certain situations (like rendering a list of 1000 items). EJS’s live binding is opt-in. It only turns on if you are using the
attr
method. If the following template binds to atodo
'sname
…… the following doesn’t setup live-binding and renders much faster …