Dealing with Jank


#1

How do Meteor developers deal with jank? I.e. pages being unresponsive and running at under 60fps?

One example of jank can be found at: https://crater.io/

It’s a flagship Meteor app, but try upvote an item in the list, whether on desktop or mobile, and it will take a good few seconds till anything happens. (I’m not here to bash any apps, my apps have the same problems, it’s more a question of how we can improve all our apps.)

This is strange, because how hard is it to update a number from 14 to 15 and then send some data to the server in the background?

Meteor, Tracker, Blaze and possibly the developer trying to do too much make this action slow and unresponsive to the user.

What are the different ways around this problem? Does switching to React alleviate these problems at all? Do the problems start when we start to use the power of Meteor’s reactiveness? Do devs have to be careful to perform less heavy operations?


Why do most Meteor applications feel "flaky?"
#2

Interesting question - I didn’t experience it at all yet, crater.io is real time fast. I just tried for the sake of this post and it’s instant. I’m on a late 2011 i7 mac book pro with 8gb ram. Maybe your machine is having too much going on at the client or some connection problem?

How is the responsiveness of other websites? What is the dns and response times in the web developer?

Regarding React it’s always been very responsive even under high load in any testing I have done / seen. But maybe on some machines this is not the case.


#3

He may be onto something for the current build. I did the same @tomtom87 and it is definitely slower than what I normally get from that site and meteor in general. I just rebooted my pc and tried again to be sure. +@joshowens


#4

Try open crater on your mobile and click the up vote button once logged in.
I know the feel changes depending on how powerful the machine you’re using
is.

Makes it difficult to debug when you’re on a very fast machine.

The problem isn’t one of network connection. The change happens locally
first and then a message gets sent to the server.

I just tested up voting on a slow windows machine using Chrome and recorded
the speed using the js timeline and it took 14000 ms! (0 fps)

My point isn’t necessarily how this specific case can be fixed. It’s one
easy to see example of a much larger problem you can run into.


#5

For this specific case, I’m guessing there’s an on click event handler that calls a meteor method, which does some checks (i.e. is logged in, etc.), updates the database to increase the vote count for the item clicked by 1, at which point all the items on the page will have to potentially be reordered based on their new scores (and the date the item was posted).

As well as all of that, a ddp message has been sent to the server to do all of that too and a response is then sent to the client whether the update was valid or not (and if invalid, that things in the UI should be undone).

That’s a lot to do! And no wonder it’s not running at 60 fps (or anywhere near 60).

Alternatively, the second the button is clicked, you could do:

document.findElementById('upvoteButton123').html = parseInt(document.findElementById('upvoteButton123').html) + 1;

(or something along those lines. Perhaps a little prettier, the exact code isn’t too important).

And after that’s been done, you could run the entire process mentioned above.

When I like a Facebook post, or heart a tweet, it doesn’t take a few hundred or thousand ms to respond, why should it be that way with Meteor apps (including my own!).


#6

It seems like there’s no latency compensation going on here. The UI is only updating once the upvote method returns from the server. May or may not be a deliberate decision but adding a client-side stub method would fix this.


#7

You tell me, if you have a username/password setup on Crater, try out the React version using the production db: http://45.55.210.81/


#8

Pretty sure Telescope has latency compensation going on for sure. I just think a lot of complex things are happening during an upvote… /cc @sacha


#9

Yeah I thought it would be weird not to have the latency compensation, it seems to only happen on my machine when the upvote causes the order to change so maybe it’s being too heavy with DOM changes somewhere.


#10

Just out of curiosity, I took the twenty seconds to run a profile on CPU usage for Crater. I loaded the page then upvoted an article. While it’s hard to be sure given the minified code, it looks like the upvote (“e” in the image below) took more time than the initial DOM render.


#11

And the other side of this hardly-scientific test… the React version. Same procedure.

Is that ~200ms difference in the event perceptible? I’d say probably, but I don’t think that’s the only factor at play. Any thoughts?


#12

I’ve always had jank on Crater when I browse it on my mobile Chrome browser. It performs fine on my desktop. I made a Crater app (telescope reader really) using React Native to no longer deal with it on my phone.

The react version performs way better. When are you going to switch to that?


#13

By the way, I know that when Sacha tweeted about it a while ago, he
mentioned React being a lot faster, but a big part of it was also that the
app was trying to do far less.

The real question was to start a discussion on improving client side
performance of meteor apps in general (and Crater was only supposed to be
an example.)


#14

Yes, the old version had some issues especially when displaying multiple nested levels of menus and submenus. Since I’m not a performance guy I fix was to switch to React. I figured at least with React, any issue I might run into would be better-documented and easier to deal with, since it has a larger user base.


#15

Was just having a look around and good to see these issues being dealt with on the Meteor level.

This one from 1.3.3. I didn’t realise it helped client side performance:


Although I still think thought has to go into speeding things up on an app by app level and common patterns to be used to speed things up.

Some ideas:

  • when calling a meteor method, don’t do all checks on the client. Use some if (Meteor.isServer) to potentially speed up client side processing. In some cases this might slow down performance because a user will have to wait for the server to repond to get feedback. If a username is too short, the client should tell the user that. However, some other checks might not be necessary on the client since the UI doesn’t allow that sort of info to be entered in any case. For example, if a client tries to make himself admin, this doesn’t have to be checked client side, only server side.

  • make imperative calls as opposed to declarative ones. i.e. do $(’#el’).value = ‘Loading’ as opposed to setting some ReactiveVar which in turn will update the text to Loading.
    This one seems like it might make the code a big mess, but I think it would help performance. Would really to do an actual test to find out.

Any other suggestions? (Or thoughts on the above?)


#16

The same principles matter for most uses. See layout reflow:

And Google’s article: https://developers.google.com/speed/articles/reflow
Also for CSS, https://csstriggers.com/

In my experience Blaze- and ReactiveVar specific slowdowns are mostly related to situations where you have an if/else block that fetches a reactive variable through a helper. This combined with any number of DOM operations makes reflow very slow in some cases. Especially if you have things reacting to mouse movement and such, try to use as few if/elses as possible.

General rule of thumb of speed has been is fetch more data and render more DOM in advance (meteorhacks:subs-manager is a very good addition here), and use CSS to hide.