how custom events will save the universe

Post on 10-Jul-2015

14.583 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

How CUSTOM EVENTS

will save the universe

Law of Demeter

“Each unit should have only limited knowledge

about other units.”

(we break this ruleall the time)

the Law of Demeter is about removing

unnecessary coupling

custom events can helpdecouple your code

Broadcaster and receiverdon’t have to knowabout one another…

… so there’s far less to mockin your unit tests

YOU DO HAVEUNIT TESTS, RIGHT?

How do custom events work?

$(document).observe('custom:event', function(event) { var customData = event.memo; // stuff}); $('troz').fire('custom:event', { foo: "bar" });

$(document).bind('customevent', function(event, customData) { // stuff}); $('#troz').trigger('customevent', [{ foo: "bar" }]);

$(document).addEvent('customevent', function(event, customData) { // stuff}); $('troz').fireEvent('customevent', { foo: "bar" });

BUT WHY?

Makes testing easier

(maybe you’ll do it now)

Why?

Rapid prototyping

Why?

More versatile than callbacks

Why?

Can be bubbled/canceled

Why?

Can handle exceptions properly(in theory)

Why?

(quoth Dean Edwards)

In Prototype,exceptions raised in one handler

won’t affect another handler

(is this a big deal? smart people disagree)

CASESTUDIES

#1

Case Studies

(script.aculo.us 2.0)

Case Studies

…as a “metronome” for effects

scripty2 uses custom events…

window.setTimeout(function() { document.fire('effect:heartbeat');}, 0);

document.observe('effect:heartbeat', advanceEffectByOneFrame);

Seems pointless…

…until you need to debug

Step through an animationframe by frame

document.observe('keydown', function(event) { if (event.keyCode === Event.KEY_RIGHT) { document.fire('effect:heartbeat'); }});

…to pass messagesbetween UI widgets

scripty2 uses custom events…

S2.UI.Menu

(used by other S2.UI components)

var menu = new S2.UI.Menu();menu.addChoice("Foo");menu.addChoice("Bar");someElement.insert(menu);menu.open();

menu.observe('ui:menu:selected', function(event) { console.log('user clicked on:', event.memo.element);});

S2.UI widgets act like elements when needed, so...

Easy to usein any context

Button with menu

ASIDE:

Custom events are cancelable

var event = $('troz').fire('custom:event');if (!event.stopped) performSomeDefaultAction();

document.observe('ui:menu:before:open', function(event) { event.stop();});

(prevent all menus from appearing)

…as hooks for debugging

scripty2 uses custom events…

“Why aren’t theseeffects queueing

like I expect?”

document.observe('effect:dequeued', function(event) { var queue = event.memo; console.log("Effects in queue:", queue.size());});

You get debuggingFOR FREE

#2

Case Studies

Mouse wheel

Case Studies

window.addEventListener('DOMMouseScroll', handler);window.onmousewheel = handler;

function handler(event) { var delta; if (event.wheelDelta) { delta = event.wheelDelta / 120; if (window.opera) delta = -delta; // (not a joke) } else if (event.detail) { delta = -event.detail / 3; }

// Do stuff with your stupid delta}

http://adomas.org/javascript-mouse-wheel/

Instead, do this:

window.addEventListener('DOMMouseScroll', handler);window.onmousewheel = handler;

function handler(event) { var delta; if (event.wheelDelta) { delta = event.wheelDelta / 120; if (window.opera) delta = -delta; // (not a joke) } else if (event.detail) { delta = -event.detail / 3; }

// Fire a custom event with the normalized delta. var result = event.target.fire('mouse:wheel', { delta: delta }); if (result.stopped) event.preventDefault();}

See also:

hashchange

#3

Case Studies

User idle state

Case Studies

credit: kangax

document.observe('state:idle', function() { turnOffBackgroundAjaxRequests();});

document.observe('state:active', function() { turnOnBackgroundAjaxRequests();});

http://perfectionkills.com/detect-idle-state-with-custom-events/

#4

Case Studies

Keyboard events

Case Studies

(function() { var KEYS = {}; KEYS[Event.KEY_ESC] = "esc"; KEYS[Event.KEY_UP] = "up"; KEYS[Event.KEY_DOWN] = "down"; KEYS[Event.KEY_LEFT] = "left"; KEYS[Event.KEY_RIGHT] = "right"; // ... and so on

function handler(event) { if (event.keyCode && KEYS[event.keyCode]) { event.element().fire("key:" + KEYS[event.keyCode], event); } }

document.observe("keydown", handler);})();

Then you’d be able to dosomething like this:

document.observe('key:left', function() { moveSlide(-1); });document.observe('key:right', function() { moveSlide( 1); });

#5

Case Studies

Data broadcasting

Server-sent events are awesome……but not universally supported

for browsers that support server-sent events

var eventSource = $('event_source');eventSource.observe('server-sent-event-name', function(event) { document.fire('data:received', event.data);});

for browsers that don’t

new Ajax.Request('/legacy/polling', { onComplete: function(request) { document.fire('data:received', request.responseJSON); }});

observer works with either approach

$(document).observe('data:received', function(event) { doStuffWithYourData(event.memo);});

…and your unit tests can fire dummy data

function testThatSomethingHappened() { document.fire('data:received', FIXTURE_DATA); assertSomething();}

FAQ

“What if my eventsaren’t DOM-related?”

FAQ

(meh)

Use the DOM anyway, I say

“Isn’t this overkill?”

FAQ

Yes, sometimes

“Aren’t events slow?”

FAQ

NO

Events aren’t slow;they’re synchronous

Events are onlyas slow as the handlers

attached to them

If performance is a concern, defer

window.setTimeout(function() { document.fire('costly:custom:event');}, 0);

QUESTIONS?

Andrew Dupont

http://andrewdupont.net

top related