Throttle and Debounce Patterns in Web Apps

Post on 27-Nov-2014

216 views 1 download

description

A brief discussion on the Throttle and Debounce Patterns. Where, when and why to use them? They solve some problems that may harm the performance of an entire web app due to misuse of user events.

Transcript of Throttle and Debounce Patterns in Web Apps

PATTERNS IN WEB APPS

THROTTLE &

DEBOUNCE

@ALMIRFILHO

@almirfilho

@loopinfinito

l8p.com.br

@almirfilho

@loopinfinito

l8p.com.br

@almirfilho

@loopinfinito

l8p.com.br

after conf

THE PROBLEM

How to control user events frequency?

onclick onresize onscroll onmousemove

SOME CASES

onclickOrder some shit

Some AJAX action. Whatever

onclickOrder some shit

Some AJAX action. Whatever

click

freak

onresizeResponsive modafoca

onresize

∆ = 100px

triggerings! !%?#$

≃ 100 *

Responsive modafoca

onscrollParalax bullshit

onscroll

∆ = 100px… same fuc*ing

thing

Paralax bullshit

onmousemoveGaming junk

onmousemove

∆x = 100px ∆y = 50px

trigg… OMG plz stop

≃ 150 *

Gaming junk

**BONUS** PROBLEM

Updating <canvas> drawings?

just redraw E-V-E -R -Y-T-H- I -N-G

Updating <canvas> drawings?

stage.update = function(){ redrawHeavyShit(); }; !

while(game.isOn){ game.step(); stage.update(); }

stupid game loop

stage.update = function(){ redrawHeavyShit(); }; !var gameLoop = function(){ game.step(); stage.update(); requestAnimationFrame(gameLoop); }; !gameLoop();

WAY COOLER

stage.update = function(){ redrawHeavyShit(); }; !var gameLoop = function(){ game.step(); stage.update(); requestAnimationFrame(gameLoop); }; !gameLoop();

WAY COOLER

Measuring damage with

dev tools

RENDERING & PAINTING COSTS

all major and modern* browsers * even in IE (11)

So, how to control user events frequency?

THROTTLE

A throttle is a mechanism to

manage fuel flow in an engine

ENGINE THROTTLE

So, throttle is just a valve?

!yeeep

resizing scrolling

mouse moving

COMMON CASES

tE E E E E E E E E E E

onscroll

paralax()

0.1s0s

tE E E E E E E E E E E

onscroll throttled

paralax()

0.1s0s

THROTTLE

tE E E E E E E E E E E

onscroll throttled

paralax()

0.1s0s

THROTTLE

var paralax = function(args){ complexHeavyShit(); }; !

window.addEventListener(‘scroll’, function(e){ paralax(e.args); });

var paralax = function(args){ complexHeavyShit(); }; !

window.addEventListener(‘scroll’, throttleParalax() );

LET’S THROOOOTLE IT

var throttleParalax = (function(){ var timeWindow = 500; var now = (new Date()).getTime(); var lastExecution = new Date(now - timeWindow); ! var paralax = function(args){ complexHeavyShit(); }; ! return function(){ var now = (new Date()).getTime(); if(lastExecution.getTime() + timeWindow <= now){ lastExecution = new Date(); return paralax.apply(this, arguments); } }; }());

var throttleParalax = (function(){ var timeWindow = 500; var now = (new Date()).getTime(); var lastExecution = new Date(now - timeWindow); ! var paralax = function(args){ complexHeavyShit(); }; ! return function(){ var now = (new Date()).getTime(); if(lastExecution.getTime() + timeWindow <= now){ lastExecution = new Date(); return paralax.apply(this, arguments); } }; }());

sets

a context

var throttleParalax = (function(){ var timeWindow = 500; var now = (new Date()).getTime(); var lastExecution = new Date(now - timeWindow); ! var paralax = function(args){ complexHeavyShit(); }; ! return function(){ var now = (new Date()).getTime(); if(lastExecution.getTime() + timeWindow <= now){ lastExecution = new Date(); return paralax.apply(this, arguments); } }; }());

sets the func.

var throttleParalax = (function(){ var timeWindow = 500; var now = (new Date()).getTime(); var lastExecution = new Date(now - timeWindow); ! var paralax = function(args){ complexHeavyShit(); }; ! return function(){ var now = (new Date()).getTime(); if(lastExecution.getTime() + timeWindow <= now){ lastExecution = new Date(); return paralax.apply(this, arguments); } }; }());

returns the event handler

Let’s visualize it

tE

500ms0s

event

happens

Let’s visualize it

t

500ms0s

E

Let’s visualize it

event executes

t

500ms0s

100msE

timeWindow

Let’s visualize it

t

500ms0s

100msE

Let’s visualize it

another event

happens

E

t

500ms0s

100msE

Let’s visualize it

no execution

E

t

500ms0s

100msE

Let’s visualize it

event

happens

E E

t

500ms0s

100msE

Let’s visualize it

same thing

now

E E

t

500ms0s

100msE

Let’s visualize itE 100msE

t

500ms0s

100msE

Let’s visualize itE 100msE E E E

DEBOUNCE

A debouncing is a technique to

guarantee that a button was pressed

only once.

ELECTRONIC DEBOUNCING

Debounce cancels multiple actions for postpone to the

last one.

clicking key pressing

COMMON CASES

tE E E E E E E E E

onkeyup

autoComplete()

1s0s

tE E E E E E E E E

onkeyup debouncing1s0s

DEBOUNCE

autoComplete()

tE E E E E E E E E

onkeyup debouncing1s0s

DEBOUNCE

autoComplete()

btn.addEventListener(‘keyup’, function(){ autoComplete(); });

btn.addEventListener(‘keyup’, debounceAutoComplete() );

LET’S DEBOOOUNCE IT

var debounceAutoComplete = (function(){ var timeWindow = 100; var timeout; ! var autoComplete = function(arg1, arg2){/* … */}; ! return function(){ var context = this; var args = arguments; clearTimeout(timeout); timeout = setTimeout(function(){ autoComplete.apply(context, args); }, timeWindow); }; }());

var debounceAutoComplete = (function(){ var timeWindow = 100; var timeout; ! var autoComplete = function(arg1, arg2){/* … */}; ! return function(){ var context = this; var args = arguments; clearTimeout(timeout); timeout = setTimeout(function(){ autoComplete.apply(context, args); }, timeWindow); }; }());

sets a context

var debounceAutoComplete = (function(){ var timeWindow = 100; var timeout; ! var autoComplete = function(arg1, arg2){/* … */}; ! return function(){ var context = this; var args = arguments; clearTimeout(timeout); timeout = setTimeout(function(){ autoComplete.apply(context, args); }, timeWindow); }; }());

sets the func.

var debounceAutoComplete = (function(){ var timeWindow = 100; var timeout; ! var autoComplete = function(arg1, arg2){/* … */}; ! return function(){ var context = this; var args = arguments; clearTimeout(timeout); timeout = setTimeout(function(){ autoComplete.apply(context, args); }, timeWindow); }; }());

return the

handler

Let’s visualize it

tE

500ms0s

event

happens

Let’s visualize it

t

500ms0s

100msE

setTimeOut

Let’s visualize it

t

500ms0s

100msE

another event

happens

E

Let’s visualize it

t

500ms0s

100msE

clearTimeOut

E

Let’s visualize it

t

500ms0s

100msE

reset

timeOut

E

Let’s visualize it

t

500ms0s

100msE E E

Let’s visualize it

t

500ms0s

100msE E E

Let’s visualize it

t

500ms0s

100msE E E

Let’s visualize it

t

500ms0s

100msE E E

cool to execute!

Let’s visualize it

t

500ms0s

100msE E E

life goes on…

E

Let’s visualize it

READ ABOUT [PT-BR]

but… <x-mimimi>

$(window).scroll($.throttle(250, paralax)); !

$('input').keyup($.debounce(250, autoComplete));

JQUERY PLUGINjquery-throttle-debounce

github.com/cowboy/jquery-throttle-debounce

UNDERSCORE.JS

underscorejs.org

$(window).scroll(_.throttle(paralax, 250)); !

$(‘input’).keyup(_.debounce(autoComplete, 250));

THANK YOU!

@ALMIRFILHO