DoneJS StealJS jQuery++ FuncUnit DocumentJS
4.3.0
5.0.0 3.13.1 2.3.35
  • About
  • Guides
  • API Docs
  • Community
  • Contributing
  • Bitovi
    • Bitovi.com
    • Blog
    • Design
    • Development
    • Training
    • Open Source
    • About
    • Contact Us
  • About
  • Guides
  • API Docs
    • Observables
      • can-bind
      • can-compute
      • can-debug
        • drawGraph
        • logWhatChangesMe
        • logWhatIChange
      • can-define
      • can-define/list/list
      • can-define/map/map
      • can-define-backup
      • can-define-stream
      • can-define-stream-kefir
      • can-event-queue
      • can-kefir
      • can-list
      • can-map
      • can-map-define
      • can-observation
      • can-observation-recorder
      • can-observe
      • can-simple-map
      • can-simple-observable
      • can-stream
      • can-stream-kefir
      • can-value
    • Data Modeling
      • can-connect
      • can-connect-feathers
      • can-fixture
      • can-fixture-socket
      • can-ndjson-stream
      • can-set
    • Views
      • can-component
      • can-stache
      • can-stache-bindings
      • can-stache-converters
      • can-stache-route-helpers
      • can-view-autorender
      • can-view-callbacks
      • can-view-import
      • can-view-live
      • can-view-model
      • can-view-nodelist
      • can-view-parser
      • can-view-scope
      • can-view-target
      • react-view-model
      • react-view-model/component
      • steal-stache
    • Routing
      • can-deparam
      • can-param
      • can-route
      • can-route-hash
      • can-route-mock
      • can-route-pushstate
    • JS Utilities
      • can-assign
      • can-define-lazy-value
      • can-diff
      • can-globals
      • can-join-uris
      • can-key
      • can-key-tree
      • can-make-map
      • can-parse-uri
      • can-queues
      • can-string
      • can-string-to-any
      • can-util
      • can-zone
      • can-zone-storage
    • DOM Utilities
      • can-ajax
      • can-attribute-encoder
      • can-child-nodes
      • can-control
      • can-dom-data
      • can-dom-events
      • can-dom-mutate
      • can-event-dom-enter
      • can-event-dom-radiochange
      • can-fragment
    • Data Validation
      • can-define-validate-validatejs
      • can-validate
      • can-validate-interface
      • can-validate-legacy
      • can-validate-validatejs
    • Typed Data
      • can-cid
      • can-construct
      • can-construct-super
      • can-data-types
      • can-namespace
      • can-reflect
      • can-reflect-dependencies
      • can-reflect-promise
      • can-types
    • Polyfills
      • can-symbol
      • can-vdom
    • Core
    • Infrastructure
      • can-global
      • can-test-helpers
    • Ecosystem
    • Legacy
  • Community
  • Contributing
  • GitHub
  • Twitter
  • Chat
  • Forum
  • News
Bitovi

can-debug

  • Edit on GitHub

Useful debugging utilities.

Object

can-debug provides methods that show how different parts of an application affect each other, specifically CanJS's observables and DOM nodes.

Exports an object with the following methods:

{
    drawGraph        // Draws the dependency graph in a new window
    logWhatIChange   // Log what the observable affects
    logWhatChangesMe // Log what affects the observable
}

Use

can-debug exports functions to log how observables affect each other. These functions can be used to understand the flow of data throughout an application.

The following example shows how to use the logWhatChangesMe function to log what affects the value of the fullName property on the me Person instance.

const Person = DefineMap.extend( "Person", {
    first: "string",
    last: "string",
    fullName: {
        get: function() {
            return this.first + " " + this.last;
        }
    }
} );

const me = new Person( { first: "John", last: "Doe" } );
debug.logWhatChangesMe( me, "fullName" );

Which prints out the following message to the browser's console:

logWhatchangesMe full output

At first, the message might be very confusing, specially so in larger examples where multiple observables are involved. Let's break it up in smaller sections to get a better understanding of what each means:

logWhatchangesMe output

The following values are printed out for each observable in the dependency graph:

  • The observable's human-readable name in the blue border box,
  • The observable's value and object reference in the red border box,
  • And finally the observable's dependencies in the green border box.

Each observable will be contained in a console group, this group is labeled using a human-readable name that describes what the the observable does (blue border box), in most cases this name is made out of the constructor name decorated with some metadata and it's returned by getName.

The box with the green border lists the dependencies of the observable in the blue border box, these dependencies are grouped based on their relation to the parent observable, in its current version can-debug outputs the following groups:

  • DERIVED FROM: observables used internally by the parent to derive its value.
  • MUTATED BY: observables that set the value of the parent observable these are mostly found inside CanJS internals, where observables interact with each other, like can-stache-bindings.
  • TWO WAY: observables that are both derived and mutation dependencies.

The observables in each group are printed out recursively using the same format we just described, We can can confirm this by expanding Person{}.fullName's dependencies group:

dependencies

The whole output can be read as:

Person{}.fullName derives its value from Observation<Person{}'s fullName getter>, which in turn derive its value from Person{}.first and Person{}.last values.

Note: Please keep in mind that some of the observables printed out in the console do not necessarily match the ones found in user's application code, as mentioned before, observables used internally are listed as dependencies, such is the case of Observation<Person{}'s fullName getter> in the example.

The following demos a live version of the previous example, click the logWhatChangesMe button and open the browser's console tab to inspect the generated message:

Understanding the relationships between types is helpful to debug certain kind of issues, but most of the time you want to understand what affects another kind of observables: DOM nodes.

The following example builds upon the previous code, and adds two <input> elements that are cross bound to the first and last properties of the Person map, then fullName is printed out in the page using a <h1> element.

Then logWhatChangesMe is called to log what observables affect the <h1> element:

const Person = DefineMap.extend( "Person", {
    first: "string",
    last: "string",
    fullName: {
        get() {
            return `${this.first} ${this.last}`;
        }
    }
} );

const template = stache( `
  <h1 id="full">{{fullName}}</h1>
  <input id="first" value:bind="first">
  <input id="last" value:bind="last">
` );

const scope = new Person( { first: "Jane", last: "Doe" } );
document.body.appendChild( template( scope ) );

debug.logWhatChangeMe( document.querySelect( "#full" ) );

This prints out the following message:

logWhatChangesMe

That's a long message! but once you have identified the output pattern, making sense of it is a lot easier. The observables highlighted in blue border boxes are the most important to get a high level overview of the dependency graph, while the observables in between help you make sense of how data flows from the top <h1> element down to each <input> element and back up to the <h1> heading element.

The following demos a live version of the previous example, click the logWhatChangesMe button and open the browser's console tab to inspect the generated message:

How to write can-debug friendly code

CanJS's internal observables are decorated with metadata and symbols used by can-debug to build the dependency graph.

For most CanJS applications, the default instrumentation should be enough to get reliable logs from can-debug; but custom observable types require some extra work to make them easier to debug.

The whole process can be sumarized in the following steps:

  • Give the observable a human-readable name, check out getName docs.
  • Register how the observable interacts with other observables, check out can-reflect-dependencies docs.

CanJS is part of DoneJS. Created and maintained by the core DoneJS team and Bitovi. Currently 4.3.0.

On this page

Get help

  • Chat with us
  • File an issue
  • Ask questions
  • Read latest news