avoid global redraw on modular view model

1k views Asked by At

how would I be able to avoid a global redraw = call to the main view function while changing the view of a submodule like in the main Module view method:

m("body", [
           m("#head", {...}),
           Menu.show(this),
           Footer.show(this)
])

where the static show method looks like :

    function show(app)
    {
        if (inst == null)
            inst = new Footer(app);
        return inst.view(app);
    }

Now it should increase the already nice performance if there is a way to run the view method of a sub view without running the main view method in case the changes in the sub view have only local effects. Does this make sense?

Axel

2

There are 2 answers

0
LeoHorie On

You can't prevent a global redraw, but you can selectively make some parts of the view not redraw by using subtree directives

Be aware however that this is a performance optimization that disables redrawing for the affected subtree, and as such, you won't be able to update its view unless you replace the directive with a subtree again.

2
Barney On

Redraw is a global operation in Mithril, and the structural decisions this forces you into are by design. Rather than expose an API which allows granular control of the view render process from any given point in the application, Mithril handles the entire process through a specialised diffing algorithm comparing iterations of an optimised virtual DOM model.

Having said that, there are ways of influencing the diffing logic and rendering implementation depending on context:

  1. Invoking m.redraw.strategy with an argument of none or diff at the right time can prevent redraw entirely or avoid what would otherwise be full DOM redraws, respectively. In my application, a particularly complex module triggers and reacts to route changes continuously (multiple lists where each item is itself a sub-moduled DOM structure, optional extra widgets, etc) – by setting m.redraw.strategy( 'diff' ) in the controller, I manage to keep performance at ~55FPS even while modifying only the chunks of the DOM that have differed (which are nonetheless large chunks!).
  2. Invoke { subtree : 'retain' } on parts of the virtual DOM you wish to remove from the diffing routine. If you have large chunks of the DOM you want the diff algorithm to ignore (and thus not be touched by subsequent redraws), you can specify this special argument in the view. Note that if you later decide to remove the subtree-retaining directive, the whole of the internal DOM tree will have to be re-rendered at least once, since previous iterations will not have been registered by the diff engine – so I wouldn't advise trying to second-guess or the diffing algorithm with this.
  3. Use { key : 'uniqueIdentifier' } to highlight elements which the diff algorithm may otherwise identify as new. If you have a chunk of the view which has moved relative to its old location in the DOM between redraws, the diffing algorithm will destroy the old one and render the new one from scratch. Specifying a unique key will allow it to ascertain that it should move the existing DOM structure instead, and apply any patches there. This is useful if a large and complex DOM structure has changed its location but starts to work against performance if used on large numbers of small items. For example, in my application I added keys to every list item (each of which was a submodule with at least 8 elements, event handlers, etc) in an attempt to avoid redrawing items which had simply moved in the list. It turned out that removing key and just creating the elements from scratch when they moved improved performance by 100%.

But my advice would be to let Mithril do what it thinks is best. One of the chief advantages of Mithril over other MVC libs' view components is that Mithril enables you to forget about the redraw cycle 90% of the time and let this happen when it needs to. This is an advantage! The other thing to bear in mind is that countless people have spent countless developer hours on trying to get Javascript MVC rendering faster – and Mithril is one of the fastest. Chances are, Mithril core is probably more optimised than second-guessing its internal logic in most circumstances. As my experience above indicates, introducing extra code to try to improve performance actually worked against my expectations. Mithril is blazingly fast as it is – this should free us up to spend our inventiveness on other problems!