Event Driven Javascript

Post on 26-May-2015

9,831 views 0 download

Tags:

description

Talk i gave at WebTech Conference on November 10th 2010. Abstract: Why is web application programming so difficult? Is it javascript fault? Is it our fault? Time to take the red pill and wake up in the real, event driven world. A world where if you can dodge the bullets of skyrocketing complexity, your programs can be made scalable, fault tolerant, extensible and just beautiful. Also http://federico.galassi.net/ http://www.webtechcon.it Follow me on Twitter! https://twitter.com/federicogalassi

transcript

• Event driven programming

• Event driven javascript• History of javascript design

Software components

exchangeinformation

Producersgive

information

Consumerstake

information

Taxonomy ofinteraction models

Who is the producer ?

KnownWhere’s Kenny?

Over There!

UnknownWhere’s Kenny?

Where’s Kenny?

Over There!

Who is the producer ?known unknown

How does information flow ?

PullWhere’s Kenny?

Over There!

PushLet me know

where’s Kenny

Ok

... later ...Hey! Over There!

How does information flow ?

known unknownpull

push

4 Models ofinteraction

known unknown

pull

push

RequestResponse

1.

Request Response

//  method  invocationweapon  =  armory.buy(“shuriken”)kenny  =  cartman.findKenny()kenny.kill(weapon)

SIMPLE

Request Response

SIMPLESEQUENTIAL

Request Response

SIMPLESEQUENTIAL

IMPERATIVE

Request Response

HUMAN

Request Response

SEQUENTIALIMPERATIVE

Request Response

TIGHT COUPLING

SEQUENTIALIMPERATIVE

Request Response

TIGHT COUPLING

INEFFICIENT

known unknown

pull

push

RequestResponse

2.

AnonymousRequest

Response

AnonymousRequest Response

The system decouplesinformation and its owner

AnonymousRequest Response

load balancer

AnonymousRequest Response

FAILOVERload balancer

AnonymousRequest Response

load balancer FAILOVER

EXTENSIBLE

AnonymousRequest Response

SYSTEMCOMPLEXITY

known unknown

pull

push

RequestResponse

3.

AnonymousRequest

Response

Callback

Callback

//  observer  patterncartman.findKenny(    function(kenny)  {        kenny.kill(weapon)})

Don’t call usWe’ll call you

From Sequential

INPUT

STATE

COMPUTATION

OUTPUT

To State MachineINPUT STATE A

OUTPUT

INPUT STATE B

INPUT STATE C

COMPUTATION

COMPUTATION

Callback

Relinquish control

Just in time is optimal

Callback

Consumer

Producers

Callback

efficiency

Callback

efficiencyEXPLICITCONTROL

FLOW

known unknown

pull

push

RequestResponse

4.

AnonymousRequest

Response

Callback Event Driven

Callback +Anonymous

Request Response=

EVENTS

Home AutomationExample

EVENTS

FAILOVER +EXTENSIBLE +efficiency =-------------------------------------

power

systemCOMPLEXITY +

explicitcontrol flow =-------------------------------------chaos

REQUEST RESPONSECALLBACK

ANON.REQUEST

RESPONSE

EVENTS

Expressive Power

Complexity

Javascriptis

event* driven

* technically callback driven

NotJavascript

Fault

NotYourFault

Just anHARDER

problem

• Event driven programming

• Event driven javascript• History of javascript design

In the old days...

Netscape HeadquartersMay 1995

This guy had two problems...

Brendan EichCreator of Javascript

1. The world isConcurrent

... and so isbrowser

Network RequestsUser Input

LiveScript first shipped in betas of Netscape Navigator 2.0 inSeptember 1995

2. Very very veryshort time

BePragmatic

He could use

Threads ...Real preemptive

concurrency

ThreadsareEvil

He could use

Coroutines ...Emulated

cooperativeconcurrency

needs acomplex

scheduler

He was afunctional

guy

Not concurrent

Take it easy

Just non-blocking

Callbacks//  callbacks  give//  non  linear  executionwally.takeJob(function  work()  ...)wally.getCoffee(function  drink()  ...)

//  ...  later  ...//  first  drink  coffee//  then  work

Simple event loop//  make  it  look  concurrentbutton.onclick(function()  {...

})

UI update

Click handler

UI update

Click handler

Click handlerUI

eventqueue

timeUser click

Non-blocking I/O//  network  async  apixhr.onreadystatechange  =  function(){...

})

//  DOM  manipulations  are  synchronous//  but  in  memory  so  very  fastdiv.innerHTML  =  “Hello”

Javascript won

Butsold its soul

for simplicity

One thread=

Freeze

No Wait()

function  breakfast()  {var  bacon  =  bacon()var  juice  =  orangeJuice()eat(bacon,  juice)

}

Simple sequential

function  bacon()  {//  get  baconreturn  bacon

}

computation

function  breakfast()  {var  bacon  =  bacon()var  juice  =  orangeJuice()eat(bacon,  juice)

}

function  bacon()  {getBacon(function(bacon)  {

//  got  bacon})

}

Async gets inwrong

return what?

Break computationfunction  breakfast()  {      var  callback  =  function(bacon)  {

var  juice  =  getOrangeJuice()eat(bacon,  juice)

}bacon(callback)

}

function  bacon(callback)  {//  get  bacon  asynccallback(bacon)

}

rest of computation

computation

Break morefunction  breakfast()  {      var  callback  =  function(bacon)  {

var  callback  =  function(juice)  {eat(bacon,  juice)

}getOrangeJuice(callback)

}bacon(callback)

}

rest of computation 1

computation

rest of computation 2

ContinuationPassing

Style

//  simple  sequential  computation

function  A()  {  return  B()  }function  B()  {  return  C()  }function  C()  {  return  value  }

A()

it’s Viral 1

it’s Viral //  C  becomes  async,  everything  becomes  async

function  A(callback)  {B(function(value)  {  callback(value)  })

}function  B(callback)  {

C(function(value)  {  callback(value)  })}function  C(callback)  {  callback(value)  }

A()

2

//  simple  sequential  sleep

sleep(3000)doSomething()

sleepit’s Hard

//  not  so  simple  sleep

setTimeout(function()  {doSomething()

},  3000)

sleepit’s Hard

//  simple  sequential  loop

images.forEach(function(url)var  image  =  fetchImage(url)image.show()

}

loopit’s Hard

//  fetchImage  is  async

images.forEach(function(url)fetchImage(url,  function(image)  {

image.show()})

}

loopit’s Hard

//  Show  them  in  the  right  order

function  processImage()  {var  url  =  images.shift()if  (url)  {

fetchImage(url,  function(image)  {image.show()processImage()

})}

}processImage()

loopit’s Hard

Javascriptsacrificed

conveniencefor simplicity

... and it was the right choice

• Event driven programming

• Event driven javascript• History of javascript design

How can we tame

complexity?

AddWait()

stupid!

Easy//  simple  sequential  sleep  with  wait/resume

sleep(3000)doSomething()

function  sleep(msec)  {wait(

setTimeout(function()  {resume()

},  msec))

}

sleep

Beautiful

Already done !

http://stratifiedjs.org/

//  write  sequential  logic

function  doOpsABC()  {waitfor  {

var  x  =  doOpA()}and  {

var  y  =  doOpB()}return  doOpC(x,y)

}

Transform tocontinuation

passingstyle

http://nodejs.org/

//  synchronous  read

fs.read(path).wait()

Implementcoroutines

Back tocomplexity

Jeremy Ashkenas - CoffeeScript

“I don't think we want to take CoffeeScript down that path. Open the Pandora's box of injecting special functions into the runtime, and ... suddenly you have to worry about being orders of magnitude slower than normal JS.”

“Case in point, Stratified JS: A virtuoso performance of JavaScript compilation, but look at what it compiles into.”

https://github.com/jashkenas/coffee-script/issuesearch?state=closed&q=asynchronous#issue/350/comment/330116

Jeremy Ashkenas - CoffeeScript

var getDocument = function(){ waitfor(document) { resume(db.get(id)); } return document; };

var getDocument;__oni_rt.exec(__oni_rt.Seq(0,__oni_rt.Seq(0,__oni_rt.Nblock(function(arguments){ getDocument=function (){ return __oni_rt.exec(__oni_rt.Seq(1,__oni_rt.Suspend( function(arguments, resume){ return __oni_rt.exec(__oni_rt.Seq(0,__oni_rt.Fcall(0,__oni_rt.Nblock( function(arguments){ return resume; }),__oni_rt.Nblock(function(arguments){ return db.get(id) }) )),arguments,this)}, function() { document=arguments[0]; }),__oni_rt.Fcall(0,__oni_rt.Return,__oni_rt.Nblock( function(arguments){ return document; }) )),arguments, this)};}))), this.arguments, this);

“I will be removing wait() in the next release of Node.It has already been removed from the documentation.”

“A proper implementation of wait() necessitates true coroutines”

“This sort of mental complication is exactly what I'm trying to avoid in Node.”

Ryan Dahl - node.js

http://groups.google.com/group/nodejs/msg/df199d233ff17efa

No wait()

Take it easy

Just control flow

Sequence//  async  sequential  computationsequence(get,  filter,  process)

function  get(resume)  {$.get(url,  function(data)  {

resume(data)})

}

function  filter(resume,  data)  {  ...  }function  process(resume,  data)  {  ...  }

1

Sequence//  async  sequential  computation

function  sequence()  {var  steps  =  arguments.slice()var  doStep  =  function(val)  {

var  next  =  steps.shift()if  (next)  {

next.apply(null,  [doStep,  val])}

}doStep()

}

2

Functional programming

first(fetchA,  fetchB,  fetchC,  callback)every(checkA,  checkB,  checkC,  callback)map(array,  mapper,  callback)filter(array,  filter,  callback)

The road is

taking yourcontrol flow

From imperative//  complex  triple  click  event

var  clicks  =  0,  timeout  =  null

$(“button”).click(function()  {clicks++if  (clicks  ==  1)  {

timeout  =  setTimeout(function()  {clicks  =  0

},  1000)}if  (clicks  ==  3)  {

clearTimeout(timeout)clicks  =  0$(this).trigger(“tripleclick”)

}})

To declarative$(button).on(“click”).times(3).within(“1  second”).trigger(“tripleclick”)

Questions?