question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

The 1.x view module’s codebase is getting increasingly harder to reason about and properly optimize. Rather than trying to fight perf death by 1,000 papercuts, I’ve decided to test a clean-slate rewrite to see what can be learned.

The current codebase does a lot of type-checking and value testing to process the JSONML templates (often in multiple places and several preprocessing passes). In addition there is the non-congruence in the template structure because everything must be in array-style declarative form. On top of that there is value coercion and other “helpful” features that are rarely used but always degrade perfomance even when they arent.

What I’ve done with the rewrite is to start with a hyperscript API & explicit child arrays that delegates some of the type-checking to the user and generates vnodes directly, reducing many allocations and preproc code. In addition, I’ve added a fluent API that can be used to set special vnode properties directly rather than forcing object allocation (though both will still be supported with different speed implications):

// 1.x
[".test", {_key: "abc"}, "hello world"];

// 2.x
h(".test", {_key: "abc"}, "hello world");     // faster than 1.x
h(".test").key("abc").body("hello world");    // fastest

// 2.x child arrays must be explicit
h(".test", [...]);
h(".test", {_ref: "myNode"}, [...]);
h(".test").ref("myNode").body([...]);

In addition to a much leaner/cleaner codebase, the performance of 2.x is significantly better than 1.x. While it’s still early and most features have not been ported. One of the things that 2.x excels at is “doing nothing”. The current 1.x branch has 3.9ms overhead at 0% mutation while 2.x is 1.5ms. This is a massive improvement, besting the current Mithril rewrite by 1.1ms (2.6ms overhead). At 50% mutation, 2.x gains an extra 5fps, going from 47fps => 52fps. The code changes are trivial:

Current JSONML implementation:

let render = (vm, dbs) =>
    ["div",
        ["table.table.table-striped.latest-data",
            ["tbody",
                dbs.map(db =>
                    ["tr",
                        ["td.dbname", db.dbname],
                        ["td.query-count",
                            ["span", { class: db.lastSample.countClassName }, db.lastSample.nbQueries]
                        ],
                        db.lastSample.topFiveQueries.map(query =>
                            ["td", { class: query.elapsedClassName },
                                ["span", query.formatElapsed],
                                [".popover.left",
                                    [".popover-content", query.query],
                                    [".arrow"],
                                ]
                            ]
                        )
                    ]
                )
            ]
        ]
    ]
};

2.x hyperscript:

let h = domvm.view.createElement;

let dbmon = (vm, dbs) =>
    h("div", [
        h("table.table.table-striped.latest-data", [
            h("tbody", dbs.map(db =>
                h("tr", [
                    h("td.dbname", db.dbname),
                    h("td.query-count", [
                        h("span", { class: db.lastSample.countClassName }, db.lastSample.nbQueries)
                    ]),
                    db.lastSample.topFiveQueries.map(query =>
                        h("td", { class: query.elapsedClassName }, [
                            h("span", query.formatElapsed),
                            h(".popover.left", [
                                h(".popover-content", query.query),
                                h(".arrow"),
                            ])
                        ])
                    )
                ])
            ))
        ])
    ])

If anyone still wishes to use JSONML (and for migration purposes), something like a domvm.jsonml module will be made to preprocess old-style templates into a properly formed vtree. This way, with known opt-in overhead, you can still use JSONML definitions:

let jml = domvm.jsonml;

var tpl = jml(["div", {},
    ["br"],
    ["table",
        ["tr"]
    ],
]);

I’m continuing to test which aspects of 1.x imposed penalties that were paid regardless of actual usage. One thing that may go away is objects as keys. this Map and Weakmap are slow, so keys will likely need to be either numbers or strings to be used in a js hash. This will allow much faster keyed matching and make destroyed view’s dom reuse possible, among other things. Another thing that may change is ancestor redraw(level) and emit(ev, args...) may be moved out to modules as they only depend on each vnode having a parent reference, so can be cleanly implemented in optional modules.

As soon as I reimplement the important aspects of the lib and rewrite the tests, I will push the 2.x branch to Github.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:1
  • Comments:54 (31 by maintainers)

github_iconTop GitHub Comments

2reactions
sabinecommented, Oct 18, 2016

Regarding prop.update(), I think that’s a convenience function that not everyone will need (or may need to work in a different way than just refetching the data, e.g. with an additional processing step for the data returned from fetch).

Maybe if there was some way to trivially implement the glue between fetch and prop and the possibility to extend prop to get something like prop.update(), it could be dropped. If it’s removed from the API, though, it should definitely be introduced in the manual on prop as an obvious and often useful way to couple prop with fetch - just like the examples of how to couple model and views.

1reaction
leeoniyacommented, Oct 21, 2016

The html and patch addons have been ported to be prototype extensions like emit: node.patch(), node.html(), vm.html(). I’ve renamed _html back to _raw as in 1.x to avoid confusion within the similar context.

Also some prelim benchmarks for 2.x-dev [1]

[1] https://cdn.rawgit.com/krausest/js-framework-benchmark/d43a0057820aac05073b917eef6317a3bd91fde8/webdriver-ts/table.html

Read more comments on GitHub >

github_iconTop Results From Across the Web

domvm 2.x-dev (part 2) · Issue #101 · domvm/domvm · GitHub
The plan is to provide a stream support for template-bound events, attr values, css prop values, ajax responses and route changes. This will...
Read more >
Android 11's power menu may turn into control center for ...
Google may be taking cues from iOS by turning the power menu in Android 11 into a control center for your favorite home...
Read more >
A Further Collection of Latin Proverbs. II - JSTOR
2, 77a a,la Naov Kai Xda,3avye: O.Tav rp or arsTov 7ravvaXXdcraoolwv. Eustath. opusc. ... salubriter nec dominum notum velis a domo sed domum...
Read more >
Untitled
Engineering disciplines list, The raid 2 berandal trailer download, Marco antonio balletta, Top comedy podcasts. Hajdinjak katja, Lg vu f200 xda, ...
Read more >
Why a Proper Smart Home Needs a Hub - How-To Geek
There are two distinct types of smart home devices. There are the devices that only need a Wi-Fi connection and an app on...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found