Knockout How to Make Observable Compute Again
Knock Me Out
Thoughts, ideas, and discussion about Knockout.js
Knockout in 2019
Hello! Are you currently developing with Knockout? Much has changed in the landscape of customer-side libraries since Knockout was considered a popular option, just there still seem to exist many successful projects using it today. I would love to hear about the interesting things that you are building with Knockout in 2019.
For the last several years, I accept been working with React on the front-end (and Node on the server-side) while working on LeanKit. So, while I accept been having lots of fun with JavaScript, I haven't had a chance to exercise anything new with Knockout lately. I would really enjoy spending time getting caught upwards and helping out in the Knockout globe.
Looking for feedback on these questions:
- What would exist useful for me to spend some time on?
- What are your biggest challenges with Knockout in 2019?
- Are there new plug-ins that could be created to solve a problem?
- Should I update many of my existing libraries to have modernistic lawmaking and a upward-to-appointment build organization?
- Any other ideas come up to listen?
Reply in the comments or send me an e-mail at ryan@knockmeout.net. Thanks!
Knockout.js three.3 Released
Knockout 3.3 is bachelor now! This release features some nice refinements to the components functionality along with a number of other small enhancements and issues fixes. The full release notes tin be found here.
In this release cycle, we welcomed Brian Chase to the core team and he has brought some great free energy and contributions to the project. Steve and Michael one time again made the bulk of the major changes in this release along with a number of other pull requests from the community.
Components refinements
We received lots of cracking feedback regarding Knockout's component functionality. Many developers seem to be having bully success using this manner of development. For 3.3, we focused on a few low-level enhancements that should provide some increased flexibility.
Synchronous Flag
Components were e'er rendered asynchronously previously, fifty-fifty when the template/viewModel were already cached. At present, the component registration tin can include a "synchronous" flag to indicate that the component should render synchronously, if it tin. In the instance where you lot have many nested components, this can assistance alleviate issues with reflows and/or flickering while rendering. The syntax would look like:
i two 3 4 v | |
Working with component child nodes
In Knockout three.iii, yous now accept options for working with the child nodes contained inside of a component. At that place are iii enhancements that go together targetting this area:
ane- The template bounden can take an array of DOM nodes directly via a nodes choice
ii- If yous are using a createViewModel function for your component, information technology will now receive the child nodes and you tin determine how to expose them on your component'due south view model for binding against the template bounden
1 2 3 4 5 6 7 8 9 10 eleven 12 thirteen fourteen | |
3- There is a new $componentTemplateNodes context variable that contains the nodes directly. In normal cases, this will allow you to avoid exposing DOM nodes in your view model and bind in the template directly.
For example, a component template might simply want to add some wrapping markup like:
1 | |
You could and then add the component to your page:
1 2 3 4 5 | |
If would still be possible to dispense (slice) $componentTemplateNodes directly in the binding, depending on the complication of the markup/scenario.
$component context variable
Sometimes inside of a component'due south template, when looping through nested structures, yous may want to bind up to the root of the component. Rather than trying to manage $parents[x], you can at present utilize $component to go the nearest components root. This is a similar concept to $root for the entire awarding, but is specific to a component.
Other Enhancements
A few other enhancements that I call back are interesting:
awake/sleep notifications from pure and deferred computeds
You can now subscribe to notifications from a pureComputed for when information technology wakes upward and for when it goes to sleep (when null depends on it). Additionally, a deferred computed now notifies when it wakes up as well. The subscriptions would expect similar:
1 two three iv 5 6 vii viii 9 10 xi 12 thirteen 14 15 xvi 17 18 xix | |
Exposing a few additional functions to the release build
-
ko.ignoreDependencies(callback, callbackTarget, callbackArgs)- executes a function and ignores any dependencies that may be encountered. This can be useful sometimes in a computed appreciable or in a custom bounden when yous want to execute code, but non trigger updates when any dependencies from that lawmaking change. Y'all would use it similar:
one | |
-
ko.utils.setTextContent(element, textContent)handles cross-browser setting the text of a node and handles virtual elements
Fixes
3.three besides includes a number of nice fixes and performance improvements listed here. This includes making the css binding work properly with SVG elements, which has been a long-standing issue.
Please bank check out Knockout 3.3.0 today! Information technology is available from GitHub, the master site, Bower (bower install knockout), and NPM (knockout).
Cleaning Up After Yourself in Knockout.js
Last summer, I had the opportunity to speak at ModernWebConf, ThatConference, and devLink on the topic of browser retention leaks. The talk was focused on the tools and techniques that you tin utilize for memory leak testing and situations in JavaScript that comonly cause these leaks. Slides for the presentation can be found hither.
With the ascent of single-page applications and increased complication (and amount) of JavaScript on the client-side, memory leaks are a mutual occurrence. Knockout.js applications are not immune to these problems. In this post, I will review some scenarios that often contribute to memory leaks and talk over the APIs in Knockout that can be used to prevent and resolve these issues.
The main source of leaks in KO
Memory leaks in KO are typically acquired by long-living objects that hold references to things that you lot expect to exist cleaned up. Here are some examples of where this tin can occur and how to make clean up the offending references:
1. Subscriptions to observables that live longer than the subscriber
Suppose that you have an object representing your overall application stored in a variable called myApp and the current view as myViewModel. If the view needs to react to the app's language observable changing, then you might make a call like:
1 | |
What this technically does is goes to myApp.currentLanguage and adds to its list of callbacks with a bound part (languageHandler) that references myCurrentView. Whenever myApp.currentLanguage changes, information technology notifies anybody by executing each registered callback.
This ways that if myApp lives for the lifetime of your application, it will keep myCurrentView around too, fifty-fifty if y'all are no longer using it. The solution, in this example, is that nosotros need to keep a reference to the subscription and telephone call dispose on information technology. This will remove the reference from the observable to the subscriber.
ane 2 three four | |
ii. Computeds that reference long-living observables
1 two 3 | |
In this case, the userStatusText computed references myApp.currentUser(). As in the subscription example, this will add to the list of callbacks that myApp.currentUser needs to telephone call when it changes, every bit the userStatusText computed will demand to exist updated.
There are a couple of means to solve this scenario:
- we tin can utilize the
disposemethod of a computed, like nosotros did with a manual subscription.
1 ii | |
- in KO 3.2, a specialized computed chosen a
ko.pureComputedwas added (docs hither). A pure computed can be created by usingko.pureComputedrather thanko.computedor by pasing thepure: trueoption when creating a normal computed. A pure computed will automatically go to sleep (release all of its subscriptions) when nobody cares almost its value (nobody is subscribed to information technology). Callingdisposeon a pure computed would probable non be necessary for normal cases, where only the UI bindings are interested in the value. This would work well for our scenario where a temporary view needs to reference a long-living observable.
3. Event handlers attached to long-living objects
In custom bindings, you lot may run into scenarios where yous demand to attach effect handlers to something like the certificate or window. Perhaps the custom bounden needs to react when the browser is resized. The target needs to keep rail of its subscribers (like an observable), so this will create a reference from something long-living (certificate/window in this case) back to your object or element that is bound.
To solve this issue, inside of a custom binding, Knockout provides an API that lets you lot execute code when the chemical element is removed by Knockout. Typically, this removal happens as function of templating or control-flow bindings (if, ifnot, with, foreach). The API is ko.utils.domNodeDisposal.addDisposeCallback and would exist used similar:
1 ii 3 4 five 6 vii viii 9 10 xi 12 thirteen | |
If you lot did not accept easy admission to the actual handler attached, then you might consider using namespaced events similar $(window).on("resize.myPlugin", handler) and then remove the handler with $(window).off("resize.myPlugin").
4. Custom bindings that wrap third-party code
The above issue is likewise commonly encountered when using custom bindings to wrap third-party plugins/widgets. The widget may non have been designed to piece of work in an surroundings where it would need to be cleaned upward (like a single-page app) or may require something like a destroy API to be called. When choosing to reference third-party code, information technology is worthwhile to ensure that the lawmaking provides an appropriate method to make clean itself up.
1 2 3 four v six vii viii 9 10 xi 12 13 14 | |
Reviewing the tools/API for clean-up in Knockout
-
disposeoffice. Can exist called on a transmission subscription or computed to remove any subscriptions to information technology. -
ko.utils.domNodeDisposal.addDisposeCallback- adds code to run when Knockout removes an element and is commonly used in a custom bounden. -
ko.pureComputed- this new type of computed added in KO 3.2, handles removing subscriptions itself when nobody is interested in its value. -
disposeWhenNodeIsRemovedoption to a computed - in some cases, you may discover it useful to create i or more computeds in theinitfunction of a custom binding to accept better control over how you handle changes to the various observables the bounden references (vs. theupdatepart firing for changes to all observables referenced. This technique tin can too let y'all to more easily share data betwixt theinitpart and code that runs when there are changes (which commonly would be in theupdatefunction.
For instance:
one 2 3 4 5 6 7 eight 9 10 11 12 xiii 14 xv sixteen 17 18 | |
Note that the instance is passing in the disposeWhenNodeIsRemoved pick to point that these computeds should automatically be tending when the element is removed. This is a convenient alternative to saving a reference to these computeds and setting up a handler to call dispose by using ko.utils.domNodeDisposal.addDisposeCallback.
Keeping track of things to dispose
One pattern that I take used in applications when I know that a item module volition ofttimes be created and torn downward is to practise these ii things:
i- When my module is beingness disposed, loop through all top-level properties and call dispose on anything that can exist disposed. Truly information technology would only be necessary to dispose items that have subscribed to long-living observables (that alive outside of the object itself), merely easy plenty to dispose of anything at the top-level when some have created "external" subscriptions.
ii- Create a disposables array of subscriptions to loop over when my module is existence disposed, rather than assigning every subscription to a top-level belongings of the module.
A snippet of a module similar this might look like:
one two 3 iv 5 half-dozen vii eight ix 10 11 12 13 14 xv 16 17 18 xix xx 21 22 23 24 25 26 27 28 29 thirty 31 32 33 | |
Decision
Memory leaks are not uncommon to find in long-running Knockout.js applications. Being mindful of how and when yous subscribe to long-living observables from objects that are potentially brusk-lived tin assist alleviate these leaks. The APIs listed in this post will aid ensure that references from subscriptions are properly removed and your applications are free of memory leaks.
Knockout.js three.ii Preview : Components
Knockout 3.2 will include some heady new functionality out-of-the-box to practise modular development through creating components. From Knockout'south point of view, a component allows you to asynchronously combine a template and data (a view model) for rendering on the page. Components in Knockout are heavily inspired past web components, only are designed to work with Knockout and all of the browsers that it supports (all the fashion back to IE6).
Components allow you to combine independent modules together to create an application. For example, a view could await like:
i two three 4 5 | |
The thought of doing modular development with Knockout is certainly not a new one. Libraries similar Durandal with its compose binding and the module binding from my knockout-amd-helpers have been doing this same type of thing for a while and have helped prove that information technology is a successful way to build and organize Knockout functionality. Both of these libraries have focused on AMD (Asynchronous Module Definition) to provide the loading and organization of modules.
Knockout's goal is to make this type of development possible as part of the core without being tied to whatever third-party library or framework. Developers will be able to componentize their code, past default, rather than just after pulling in diverse plugins. However, the functionality is flexible plenty to support unlike or more advanced ideas/opinions through extensibility points. When KO 3.2 is released, developers should seriously consider factoring components heavily into their application compages (unless already successfully using 1 of the other plugins mentioned).
How does it work?
By default, in version iii.two, Knockout will include:
- a system for registering/defining components
- custom elements as an easy and clean way to render/consume a component
- a
componentbounden as an culling to custom elements that supports dynamically binding against components - extensibility points for modifying or augmenting this functionality to suit individual needs/opinions
Let's accept a look at how this functionality is used:
Registering a component
The default component loader for Knockout looks for components that were registered via a ko.components.register API. This registration expects a component proper name along with configuration that describes how to determine the viewModel and the template. Hither is a simple example of registering a component:
1 2 3 four 5 half-dozen | |
The viewModel key
- tin can exist a role. If and so, then it is used as a constructor (called with
new). - can pass an
instanceproperty to use an object directly. - tin can pass a
createViewModelproperty to call a role that can act every bit a mill and return an object to use equally the view model (has admission to the DOM element every bit well for special cases). - can laissez passer a
cravefundamental to call thecravefunction with the supplied value. This volition work with whatever provides a global require function (likerequire.js). The result volition over again get through this resolution process.
Additionally, if the resulting object supplies a dispose function, and then KO will call it whenever fierce down the component. Disposal could happen if that office of the DOM is being removed/re-rendered (by a parent template or command-menstruation binding) or if the component binding has its proper noun inverse dynamically.
The template key
- tin can be a string of markup
- tin can exist an array of DOM nodes
- tin be an
elementbelongings that supplies the id of an chemical element to utilise as the template - can be an
elementbelongings that supplies an element straight - can exist a
craveproperty that like forviewModelwill telephone callrequiredirectly with the supplied value.
A component could choose to just specify a template, in cases where a view model is non necessary. The supplied params will be used every bit the data context in that instance.
The component binding
With this functionality, Knockout will provide a component bounden as an selection for rendering a component on the folio (with the other selection being a custom chemical element). The component binding syntax is fairly elementary.
1 2 3 4 5 | |
The component binding supports binding against an observable and/or observables for the name and params options. This allows for handling dynamic scenarios like rendering different components to the principal content area depending on the state of the awarding.
Custom Elements
While the component bounden is an easy way to display a component and will be necessary when dynamically binding to components (dynamically changing the component name), custom elements volition probable be the "normal" fashion for consuming a component.
ane | |
Matching a custom element to a component
Knockout automatically does all of the necessary setup to brand custom elements work (even in older browsers), when ko.registerComponent is called. By default, the chemical element proper name will exactly match the component name. For more than flexibility though, Knockout provides an extensibility point (ko.components.getComponentNameForNode) that is given a node and expected to return the proper noun of the component to use for information technology.
How params are passed to the component
The params are provided to initialize the component, similar in the component binding, simply with a couple of differences:
- If a parameter creates dependencies itself (accesses the value of an appreciable or computed), then the component will receive a computed that returns the value. This helps to ensure that the entire component does non need to be rebuilt on parameter changes. The component itself can command how it accesses and handles whatever dependencies. For example, in this case:
1 | |
The component will receive a params object that contains a name property that is supplied as a computed in this case. The component can and then determine how to best react to the name changing rather than but receiving the result of the expression and forcing the entire component to re-load on changes to either of the observables.
- The
paramsobject supplied when using the custom element syntax will besides include a$rawholding (unless theparamshappens to supply a property with that same name) which gives admission to computeds that return the original value (rather than the unwrapped value). For case:
1 | |
In this case, since selectedItem is accessed, the param is supplied as a computed. When the computed is accessed, the unwrapped value is returned to avoid having to double-unwrap a param to become its value. However, you may want access to the value observable in this case, rather than its unwrapped value. In the component, this could exist accomplished by accessing params.$raw.value(). The default functionality is slanted towards ease of apply (non having to unwrap a param twice) while providing $raw for advanced cases.
Custom loaders
Knockout let's y'all add multiple "component loaders" that can choose how to sympathize what a component is and how to load/generate the DOM elements and data.
A loader provides ii functions: getConfig and loadComponent. Both receive a callback argument that is called when the function is fix to proceed (to support asynchronous operations).
-
getConfigcan asynchronously return a configuration object to describe the component given a component name. -
loadComponentwill have the configuration and resolve information technology to an array of DOM nodes to apply as the template and acreateViewModelfunction that volition directly return the view model case.
The default loader
To understand creating a custom component loader, it is useful to get-go understand the functionality provided by the default loader:
The default getConfig function does the following:
- this function but looks up the component name from the registered components and calls the callback with the defined config (or cypher, if it is not defined).
The default loadComponent function does the following:
- tries to resolve both the
viewModelandtemplateportions of the config based on the various means that information technology can be configured. - if using
requirewill phone callrequirewith the configured module name and will take the upshot and go through the resolution process once more. - when information technology has resolved the
viewModelandtemplateit will return an array of DOM nodes to use every bit the template and acreateViewModelfunction that will render a view model based on however theviewModelproperty was configured.
A sample custom loader
Permit's say that nosotros want to create a widget directory where we place templates and view model definitions that we want to require via AMD. Ideally, we want to just be able to do:
i | |
In this case, we could create a pretty unproblematic loader to handle this functionality:
1 two 3 4 5 6 7 8 9 x 11 12 13 14 15 16 17 xviii nineteen 20 21 22 23 24 25 26 27 28 | |
In this custom loader, nosotros merely dynamically build the configuration that we desire, and then we don't necessarily have to register every "widget" as its own component, although registering will properly setup custom elements to work with the component. Loading the widget-i component would load a ane.js view model and one.tmpl.html template from a widgets directory in this sample loader. If the component is non a "widget", then the callback is chosen with null, so other loaders can try to fulfill the asking.
Summary
Components are a major improver to Knockout's functionality. Many developers take institute ways to do this type of development in their applications using plugins, but information technology will be great to have standard back up in the cadre and the possibility for extensibility on top of it. Steve Sanderson recently did a dandy presentation at NDC Oslo 2022 that highlighted the use of components in Knockout. Bank check it out hither.
Knockout 3.2 is well underway and should exist set for release this summer.
How Does Dependency Detection Work in Knockout.js?
I received a question over email request about how Knockout's dependency detection really works and thought that I would share an answer in this post. I know that I feel a bit uncomfortable whenever a library that I am using does something that I don't fully understand, and so I hope that I can assist ensure that this role of Knockout is not misunderstood or considered "magic".
A few questions to answer:
- For a computed appreciable, how does KO know which dependencies should trigger a re-evaluation of the computed on changes?
- How is it possible for the dependencies to change each time that a computed is evaluated?
- For bindings, how are dependencies tracked?
Determining dependencies for a computed
TLDR: Knockout has a middle-man object that is signalled on all reads to computed/observables and tells the electric current computed beingness evaluated that it might desire to hook up a subscription to this dependency.
-
Internally Knockout maintains a unmarried object (
ko.dependencyDetection) that acts every bit the mediator between parties interested in subscribing to dependencies and dependencies that are being accessed. Let's call this object the dependency tracker. -
In a block of code that wants to runway dependencies (like in a computed's evaluation), a call is made to the dependency tracker to signal that someone is currently interested in dependencies. As an example, permit's simulate what a computed would call:
1 2 3 4 5 half dozen 7 viii 9 x 11 | |
- Any read to an observable or computed triggers a call to the dependency tracker. A unique id is then assigned to the observable/computed (if it doesn't have i) and the callback from the currently interested party is passed the dependency and its id.
1 2 3 4 5 | |
- The dependency tracker maintains a stack of interested parties. Whenever a call is made to starting time tracking, a new context is pushed onto the stack, which allows for computeds to exist created inside of computeds. Any reads to dependencies will go to the electric current computed being evaluated.
1 2 three iv 5 6 7 viii nine 10 11 12 thirteen 14 | |
- When a computed is done evaluating, it signals the dependency tracker that is is complete and the tracker pops the context off of its stack and restores the previous context.
1 two 3 four 5 six 7 eight 9 x eleven | |
- When an observable/computed dependency is updated, then the subscription is triggered and the computed is re-evaluated.
Here is a jsFiddle version of this code: http://jsfiddle.internet/rniemeyer/F9CrA/. Note that ko.dependencyDetection is only exposed in the debug build. In the release build information technology is renamed as part of the minification process.
And then, Knockout doesn't need to parse the function as a cord to determine dependencies or practise any "tricks" to brand this happen. The cardinal is that all reads to appreciable/computeds go through logic that is able to point the dependency tracker who tin can let the computed know to subscribe to the observable/computed.
How can dependencies change when a computed is re-evaluated?
Each time that a computed is evaluated, Knockout determines the dependencies once again. For any new dependencies, a subscription is added. For any dependencies that are no longer necessary, the subscriptions are disposed. Generally, this is efficient and beneficial as long every bit you are simply branching in computed code based either data that is appreciable or doesn't change. For example:
1 2 three 4 5 half dozen 7 viii 9 10 xi | |
In this example, when showErrors is simulated, this computed will only accept a single dependency, showErrors. There is no need to depend on the history or trigger re-evaluation when the items change, every bit information technology volition non influence the result of the part. If showErrors does become truthy, and so the computed volition depend on showErrors, the history observableArray, and the type of each item.
What about bindings? How do they track dependencies?
Bindings in Knockout actually utilize computeds as a tool to facilitate their ain dependency tracking. Each binding is evaluated within a computed observable for this purpose. Observables/computeds accessed in the update function of a binding become dependencies. Observables that are accessed within a binding cord (like items in data-bind="if: items().length") are read when the valueAccessor() part is called (or via allBindingsAccessor - allBindingsAccessor.go("if") in this instance). I think that information technology is useful to think of a binding's update function just like a normal computed observable where access to any dependencies will trigger the binding to run once again.
Note: Prior to KO 3.0, all bindings on a single chemical element were wrapped within of a single computed. The parsing and evaluation of the binding cord was also included in this computed. So, calling valueAccessor() would give the consequence of the expression rather than actually run the code. Dependency detection worked the same way, all bindings on an element were triggered together and it was not possible to isolate dependencies made in the binding string. Encounter this post for more than details.
Something new in KO 3.2 - ko.pureComputed
At that place is an interesting characteristic coming in KO three.ii related to computed dependency tracking. Michael All-time implemented an option that allows a computed to non maintain any dependencies when it has no subscribers to it. This is not appropriate for all cases, but in situations where the computed returns a calculated value with no side-effects, if in that location is nada depending on that calculated value, and so the computed can get to "sleep" and not maintain subscriptions or be re-evaluated when any of the dependencies change. This will be useful for efficiency besides as potentially preventing memory leaks for a computed that was not tending, but could be garbage collected if information technology was not subscribed to something observable that still exists. The option is chosen pure and a ko.pureComputed is provided equally a shortcut.
Copyright © 2022 - Ryan Niemeyer - Powered by Octopress
Source: http://www.knockmeout.net/
0 Response to "Knockout How to Make Observable Compute Again"
Post a Comment