JavaScript Performance at Fluent Conf
There was also a pretty good selection of talks concerning performance at Fluent Conf this year.
The Perception of Speed
Steve Souders, @souders
Quick side note: Steve Souders very recently left Google. In fact, he had been at his new position with Fastly for a whopping two days before he gave this talk. This talk was possibly my favorite talk of the entire conference.
Our perception of speed is in many cases unrelated to the actual speed of things:
It is not uncommon for civilian signal buttons to be installed that do nothing, but still make the person feeled empowered. In NYC, about 3/4 of all crosswalk buttons are disconnected. The London underground has open/close buttons next to doors, but they do nothing. Only the driver of the train can open and close doors.
People at Houston Internation Airport had lots of complaints about how long luggage took to get to carousels. Airport officials did some research and found:
- On average, people took 1 minute to get to the caurosel and then waited 7 minutes to get their bags
- Decreasing the actual time the bags took to get to the caurosel had little impact on the number of complaints
- Instead, IAH added diverters and increased how long it took people to walk to the caurosel, and the complaints went away
Mirrors and (now) TVs are placed in and around elevators to give people something else to focus on while waiting, thus reducing their annoyance. Disney is masterful at this sort of psychology based planning:
- They overestimate wait time displayed on their counters
- They set up their lines so you can't see all of it at once, and thus have no idea how long they actually are
Coinstar found that their machines counted change so fast that people doubted the accuracy of the machines. They added a counter to slow the screen update rates and even play coin sounds to make it sound like it’s still working
In a 2001 study, Amazon was found to feel the fastest but was actually the slowest among top internet destinations.
Similar tricks are employed with the web. Browsers don’t show the next (blank) page immediately after a link is clicked because it increases user aggrevation, instead waiting for body.onload
to be fired.
When it comes to web design, if you are using an async mechanism that is ultimately synchronous from a UI flow perspective, show an indicator.
- It’s better to show an indicator at the area of focus (whatever was just clicked/tapped), than at the edge of the page
- WebViews and native mobile apps are especially egregious because there are no built-in busy indicators like browsers have
Spinners and progress bars are only so good. “Natural” progress indicators are better. As an example, look at the Google search app in Android. When a link is clicked, it slides a new page across old one, with speed of translation being related to loading speed (apparently).
Tips for reducing the feeling of waiting:
- Updates UI as soon as user action takes place
- Lay out a page with placeholders for slow-loading items (e.g. large images) so everything is sized before data comes in
- Show something, anything, for the user to look at that will keep them engaged. Text is great for this because it transfers quickly and it takes time for people to read.
- The instagram website handles this very well
- They set background color of placeholder to match base color in the image
- They display the metadata for the image (size, user, location, etc)
Inside JavaScript Execution
Chase Douglas, @txase
I did not like this talk, to the point I found it aggravating. It wasn't comprehensive, and instead focused on some areas that felt haphazardly chosen. What's worse, some of this information was just flat out wrong!
As an example, he discussed what engines do when you have this code:
function foo() {
this.x = 10;
this.y = 20;
}
var bar = new foo();
var.z = 30;
First of all, he called foo
a class. Prototypes are not classes!
Second, he said that by assigning a value to z
, the engine under the hood had to calculate a new class called foo*
, and that assigning properties to an instantaited class is a performance hit. This is partly true, but only if you define your properties on the prototype, which he does not do above. To get the better performance, you need to declare your class as:
function foo() {}
foo.prototype.x = 10;
foo.prototype.y = 20;
foo.prototype.z = 20;
It was frustrating...what makes it worse is that he's implanting ideas like "JavaScript has classes" in peoples heads, when in fact it doesn't. It's not just semantics either because it's going to confuse people when actual classes land in ECMAScript 6.
Secrets of the Virtual DOM
Pete Hunt @floydophone
Why is developing UIs difficult? Errors usually aren't of the form "your code crashed in file x at line y", but more often of the form "It just doesn't feel right." As a result, UIs require lots of human verified testing because they often contain lots of state. TDD is pretty much a non-starter as a result. Reducing complexity of code is usually the best way to reduce the errors in UI code.
The current approach to reducing complexity in web apps is to use data binding with a Model-View-Controller architecture. Data binding mechanisms in existing MVC systems try very hard to abstract away a lot of details from developers. This leads data-binding to being powerful, and fairly productive to work with, but are non-trivial in practice
"All non-trivial abstractions, to some degree, are leaky." - Joel Spolsky
MVC patterns tend to lead to a separation of concerns that shouldn't necessarily be separated, and don't separate certain things that should be. The ideal with MVC is that the any one piece doesn't really know or care much about the other pieces, but in practice the coupling is a lot tighter. Models and views in web-based MVC systems (which are usually just MV or MV* in practice) tend to be very closely coupled together. Often, views tell models when to fetch, what to set, etc, such that models are little more than dumb data recepticals with some networking logic in these cases.
Proper separation of concerns is paramount in creating maintainable code. The reason being that proper separation of concerns leads to lots of simple modules that are easy to test in isolation. A major problem, though, is that simple does not always mean the same thing as familiar.
“Programmers know the vale of everything and the cost of nothing” - Alan Perlis
MVC patterns are very familiar, but are they really simple? There are a lot of things that you just have to know with MVC systems, because the data flow through an application is obscured.
This line of thinking led Facebook to create a framework that eschews MVC entirely called React
In React, you create all of your DOM nodes in JavaScript, which allows devs to come up with the best separation of concerns, instead being forced into a predefined separation of concerns. It also makes it much easier to reason about JS programs since code for a single widget on screen isn't spread across 3, 4, 5 files.
So what does this have to do with performance? As it turns out, React has another trick up its sleave: a virtual DOM.
Every web developer knows that DOM manipulations are slow, but how do we deal with it? In practice, web apps in modern MVC frameworks are composed of a hodgepodge of code that data binds using a variety of mechanisms: updating single DOM nodes on a case-by-case basis, re-rendering an entire control, etc. Choosing the right one falls on the shoulders of the front-end developer. This case-by-case basis tends to be rather error-prone.
React takes a different approach: they have what they call a "virtual" DOM that is a pure in-memory representation of the actual DOM that is very very fast. Whenever data changes, the entire virtual DOM is re-rendered, which is a fast operation. The React implementation then performs a diff between the virtual DOM and the real DOM, and only updates what changed.
The advantage of this method is that the onus of performance is no longer on the front-end dev, but rather on the React devs. Optimizations only have to be done once, on React, instead of over and over and over in the code that uses React. As a result, React is much faster than Ember and Angular in most cases.
"Simplicity is the ultimate sophistication" - Leonardo DaVinci
The virtual DOM apprach is simpler, smaller, and usually more performant than MVC.