JavaScript on the Desktop
Fast and Slow
Felix Rieseberg
Senior Staff Engineer, Slack
www.felix.fun
CGI
Battlefield 1
Nvidia GeForce Experience
Adobe
Creative Suite
All the Electron Apps
Slack
Visual Studio Code
Skype
Xbox
WhatsApp
Figma
WordPress
Visual Studio Installer
Dropbox
Hyper
Cypress
GitHub Desktop
Atom
Discord
Postman
Docker
Microsoft Teams
OpenFin
ChartIQ
Zeplin
Zeit Now
WebTorrent
Performance
💾
Memory
⏱
Speed
🔋
Energy
Measure & Monitor
Modules
const isReachable = require('is-reachable')
async function isFrontmaniaReachable() {
const reachable = await isReachable('frontmania.com')
console.log(reachable)
}
Modules
94000
Lines of JSON
const isReachable = require('is-reachable')
async function isDotReachable() {
const fmReachable = await isReachable('frontmania.com')
console.log(dotReachable)
}
Modules
// Don't require the module until you need it
// require() caches results
async function isDotReachable() {
const isReachable = require('is-reachable')
const fmReachable = await isReachable('frontmania.com')
console.log(fmReachable)
}
// Do you even need a module?
function isReachable() {
return new Promise((resolve, reject) => {
const http = require('http')
http.get('http://frontmania.com', () => {
resolve()
}).on('error', (e) => {
reject(e)
})
})
}
#!/usr/bin/env node
'use strict';
[...]
try {
require(__dirname + '/../lib/v8-compile-cache.js');
} catch (err) {
}
[...]
V8 Code Caching
require('v8-compile-cache')
async function isFrontmaniaReachable() {
// The "compiled" blobs are now cached
// Have V8 parse the module only once
const isReachable = require('is-reachable')
const dotReachable = await isReachable('frontmania.com')
console.log(dotReachable)
}
V8 Code Caching
babel-core
yarn
yarn (bundled)
218ms
153ms
228ms
185ms
113ms
105ms
https://github.com/zertosh/v8-compile-cache/tree/master/bench
Rendering
window.requestAnimationFrame(() => {
// Perform work that'll result in visual changes
animate();
})
Optimize visual changes
Benchmarks
// Option 1
const divs = document.querySelectorAll('.test-class')
// Option 2
const divs = document.getElementsByClassName('test-class')
// 🤔 Which one is faster? And by how much? Let's find out:
// https://jsperf.com/dotjs-perf-example
Not all code is equal
document.querySelectorAll('.test-class')
375,363 ops/sec
± 5.27%, 99% slower
document.getElementsByClassName('test-class')
29,318,183 ops/sec
± 0.55%
Demo
#include <nan.h>
NAN_METHOD(IsPrime) {
if (!info[0]->IsNumber()) {
Nan::ThrowTypeError("Argument must be a number!");
return;
}
int number = (int) info[0]->NumberValue();
if (number < 2) {
info.GetReturnValue().Set(Nan::False());
return;
}
for (int i = 2; i < number; i++) {
if (number % i == 0) {
info.GetReturnValue().Set(Nan::False());
return;
}
}
info.GetReturnValue().Set(Nan::True());
}
NAN_MODULE_INIT(Initialize) {
NAN_EXPORT(target, IsPrime);
}
NODE_MODULE(addon, Initialize);
Go Native
// Brought to you by Parcel:
// Import a wasm file like it's no big deal
const { add } = await import('./add.wasm')
const result = add(2, 3)
// 🙀 Same trick, but with Rust
const { add } = await import('./add.rs')
const result = add(2, 3)
// Rust, a true teamplayer
#[no_mangle]
pub fn add(a: i32, b: i32) -> i32 {
return a + b
}
App Lifecycle
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// Suspend all expensive operations
// 🔪 setInterval()
// 🔪 Animations
// 🔪 Not-urgent network requests
} else {
// Continue!
}
})
Background
window.requestIdleCallback(() => {
// Perform non-important work that should not
// impact the user's experience
sendPerformanceTelemetry()
}, {
timeout: 2000
})
De-prioritize work
const { Worker } = require('worker_threads')
export function resizeImage(image, size) {
return new Promise((resolve, reject) => {
const worker = new Worker(__dirname + "/worker.js", {
workerData: { image, size }
})
worker.on('message', resolve);
worker.on('error', reject);
})
}
Multithreading
Polyfills
Thank you!
Say Hi!
@felixrieseberg or www.felix.fun
FrontMania: JavaScript on the Desktop, Fast and Slow
By Felix Rieseberg
FrontMania: JavaScript on the Desktop, Fast and Slow
- 880