Tips, Tricks & Hacks

in the pursuit of


Neil Jenkins / @neilj

Opera Software / FastMail

Computers should wait on users, not vice versa

What's slow?

  1. Network
    • Latency
    • Bandwidth
  2. DOM
    • Layout/reflow
    • Repaint

What's not slow?


* Use of O(n2) algorithm with large data set excluded.

You should still profile.

Part I:
Network Effects

Minification & Concatenation

  • Minification – reduce bandwidth usage
  • Concatenation – minimise latency
  • Compress JS + CSS + Images

Speed tip:

Never put off to run-time what you can do at compile time.

Load Less

(especially upfront)

Load in Parallel

(only one <script> in the page)

Use a loader like

Cache Aggressively

  • Trick: Add MD5 of file contents to name
  • Trick: Cache in localStorage to take control of caching strategy


  • Make use of that idle network
  • Predict the future.

Optimistic Updates

  • Presume success
  • Reset if wrong

API Design

  • REST is slow (heresy!)
  • Data is often small. Latency overhead is large
  • Let's concatenate & minify

Delta updates – API minification

Efficiently update a large collection of data

User ID Title IsDone
1 56 Take laundry to the cleaners T
1 58 Pick up laundry F

User Table Modseq
1 Todo 42
2 Todo 5
User ID Title IsDone ModSeq DeletedAt
1 47 Buy clothes F 41 2013-06-12T00:00Z
1 56 Take laundry to the cleaners T 42 Null
1 58 Pick up laundry F 40 Null
User Table Highest Modseq Lowest Modseq
1 Todo 42 3
2 Todo 5 0

Modifying the data

  1. Before modifying, first increment highest modseq for user/table in the metatable (and lock row for duration of transaction).
  2. Then
    • Create: Add row to table with the new highest modseq
    • Update: Update row in table with new data and update modseq to new highest value
    • Delete: Update row in table to new highest modseq value and add timestamp to deleted column.
  3. Periodically scan table and remove rows with a deleted timestamp older than (say) 7 days. If modseq of row is > lowest modseq in metatable, update the metatable.

Querying the data

  • When returning data, also return the highest modseq (from metatable) + highest ID from table.
  • To refresh, send (highest modseq, highest ID) to server.
    1. If client modseq == highest modseq, nothing changed. Abort early
    2. If client modseq < lowest modseq, cannot accurately calculate change, force full refresh.
    3. Otherwise…


  1. Select all rows for user with modseq > client modseq.
  2. If row ID > client highest ID:
    • If DeletedAt != null, ignore
    • Else, add to created list
  3. Else if DeletedAt != null, add to deleted list
  4. Else, add to changed list

For large data

  • Sort on the server.
  • Return window
  • Return index with created/changed
  • Can apply delta update to partial data in the client

Some other time…

Part II: The DOM strikes back

Thank You