SANS
GERARD
Developer Evangelist
Developer Evangelist
International Speaker
Spoken at 164 events in 37 countries
Serverless Training
Serverless Training
Browser Performance
DOM events
HTTP Requests
Asynchronous Web APIs
setTimeout setInterval
Promises async/await
Woot!? Event Loop?
Macro & microtasks Quiz
const log = console.log;
const macro = v => setTimeout(() => log(v));
const micro = v => Promise.resolve().then(() => log(v));
log(1);
macro(2);
micro(3);
log(4);
a) 1 2 3 4
b) 1 4 2 3
c) 1 4 3 2
Event Loop waits for microtasks
JavaScript: call me maybe?
setTimeout Quiz
setTimeout(() => log(1));
setTimeout(() => log(2), 0);
log(3)
// a) 1 2 3
// b) 3 2 1
// c) 3 1 2
YAY!
setTimeout Quiz
setTimeout(() => log(1), 1000);
setTimeout(() => log(2), 2000);
setTimeout(() => log(3), 3000);
// a) 1 2 3 (wait aprox. 1s)
// b) 1 2 3 (wait aprox. 3s)
// c) 1 2 3 (wait aprox. 6s)
setInterval(task, 50)
Time
50ms
task 1
task 2
task 3
task < delay
setInterval(task, 50)
Time
50ms
task 1
task 2
task 3
task > delay
task 1
task 2
task 3
Reality
Ideal
Delay is only timer to enter Event Loop
RxJS help me!
audit auditTime buffer bufferCount bufferTime bufferToggle bufferWhen catchError combineLatestAll combineLatestWith concatAll concatMap concatMapTo concatWith connect count debounce debounceTime defaultIfEmpty delay delayWhen dematerialize distinct distinctUntilChanged distinctUntilKeyChanged elementAt endWith every exhaustAll exhaustMap expand filter finalize find findIndex first groupBy ignoreElements isEmpty last map mapTo materialize max merge mergeAll mergeMap mergeMapTo mergeScan mergeWith min observeOn onErrorResumeNext pairwise raceWith reduce repeat repeatWhen retry retryWhen sample sampleTime scan sequenceEqual share shareReplay single skip skipLast skipUntil skipWhile startWith subscribeOn switchAll switchMap switchMapTo switchScan take takeLast takeUntil takeWhile tap throttle throttleTime throwIfEmpty timeInterval timeout timeoutWith timestamp toArray window windowCount windowTime windowToggle windowWhen withLatestFrom zipAll zipWith
98 operators
rxjs.dev
Basic Example
of(1, 2, 3)
.subscribe(
v => console.log(v)
);
1
2
3
Synchronous Operators
Synchronous by default
- Examples: of, from, range
- Default Scheduler: queue
Asynchronous Operators
Asynchronous by default
- Examples: timer, interval
- Scheduler: async
- Primitive: setInterval
Changing default Scheduler
of(1).subscribe(v => l(v));
l(2);
// 1 2
import { asyncScheduler } from 'rxjs';
of(1, asyncScheduler).subscribe(v => l(v));
l(2);
// 2 1
Least Concurrency Principle
Queue Scheduler
Overview
- Executes Synchronously
- Tasks execute in order
- Waits until current task ends before executing next one
- Performant (precedes Event Loop)
QueueScheduler Example
import { queueScheduler } from 'rxjs';
queueScheduler.schedule(() => log(1));
log(2);
queueScheduler.schedule(() => log(3));
// 1 2 3
queueScheduler.schedule(() => {
queueScheduler.schedule(() => log(1));
log(2);
queueScheduler.schedule(() => log(3));
});
// 2 1 3
Asap Scheduler
Overview
- Executes Asynchronously (micro)
- Tasks execute before next tick
- Relays on Promises
- Performant (precedes Event Loop)
AsapScheduler Example
import { asapScheduler } from 'rxjs';
import { queueScheduler } from 'rxjs';
setTimeout(() => log(1));
asapScheduler.schedule(() => log(2));
queueScheduler.schedule(() => log(3));
// 3 2 1
Async Scheduler
Overview
- Executes Asynchronously (macro)
- Relays on setInterval
- Less performant (uses Event Loop)
AsyncScheduler Example
import { asyncScheduler } from 'rxjs';
import { queueScheduler } from 'rxjs';
asapScheduler.schedule(() => log(2));
asyncScheduler.schedule(() => log(1));
queueScheduler.schedule(() => log(3));
// 3 2 1
Animations Scheduler
Overview
- Executes Asynchronously
- Relays on requestAnimationFrame
- Adapts to Device Frame Rate
- Slows down when is not active
- Balances CPU/GPU load
DURATION
Animations
0%
100%
KEYFRAMES
Frame Rates
60 FPS
Time
16.66ms
16.66ms
16.66ms
1000/60ms
paint
frame
paint
frame
paint
frame
Stutter or Losing Frames!
60 FPS
Time
16.66ms
16.66ms
16.66ms
paint
frame
paint
frame
paint
frame
using setInterval
const token = setInterval(paintFrame, 1000/60);
const paintFrame = () => {
// animation code
}
setTimeout(() => clearInterval(token), 40);
Issues
- Ignores Device Frame Rate
- Runs all the time (batteries enemy)
- Ignores current CPU/GPU load
requestAnimationFrame
60 FPS
Time
16.66ms
16.66ms
16.66ms
1000/60ms
paint
frame
paint
frame
paint
frame
requestAnimationFrame
let token = requestAnimationFrame(paintFrame);
const paintFrame = (timestamp) => {
// animation code
token = requestAnimationFrame(paintFrame)
}
setTimeout(() => cancelAnimationFrame(token), 40);
animationFrames (RxJS)
let state = { angle: 0 };
const div = document.querySelector('.circle');
animationFrames().pipe(
tap(render)
).subscribe();
function render({ timestamp, elapsed }) {
let { angle } = state;
state = { angle: ++angle % 360 };
(div as HTMLDivElement).style.transform = `rotate(${angle}deg)`;
}
Wrapping up
Schedulers priorities RxJS
# | Type | Execution | Primitives |
---|---|---|---|
1 | queueScheduler | Sync | scheduler.schedule(task, delay) scheduler.flush() |
2 | asapScheduler | Async (micro) | Promise.resolve().then(() => task) |
3 | animationFrameScheduler | Async (rAf) | id = requestAnimationFrame(task) cancelAnimationFrame(id) |
4 | asyncScheduler | Async (macro) | id = setInterval(task, delay) clearInterval(id) |
Next tick - Next tick - Next tick - Next tick - Next tick - Next tick
stackblitz.com/@gsans
Unleash Fast&Furious performance with RxJS
By Gerard Sans
Unleash Fast&Furious performance with RxJS
Did you ever notice your laptop going cray-cray after you open a Web Page? Usual suspects are animations, heavy duty framework bootstrap, using setTimeout/setInterval without a Developer license?!? There's certainly a mysterious side of JavaScript that deals with concurrency, asynchronous processing and high performance that can go terribly wrong. In this talk we are going to put the event loop under the microscope and really look at what is happening behind the scenes. Will we cover macro and microtasks? Yep. We are going to roll our sleeves up and use RxJS to deal with concurrency. Instead of creating microtasks we will use RxJS Schedulers elegant abstraction to improve performance without losing control. Let's avoid more CPUs cycles going to waste today!
- 2,265