KEMBAR78
响应式编程及框架 | PDF
Reactive Programming
   and Framework
   Zhao Jie - SNDA - Sep. 2010
About me
     /      / Jeffrey Zhao /



Blog: http://blog.zhaojie.me/

Twitter: @jeffz_cn

F#, Scala, JavaScript, Python, .NET, mono...

Java (as the language) hater
What?

Fundamentally change the way you
   think about coordinating and
  orchestrating asynchronous and
     event-based programming
Why?

   Because the essence of
      Cloud, Web, Mobile
is asynchronous computations
How?

By showing that asynchronous and
 event-base computations are just
      push-based collections
Interactive & Reactive
a := b + c
Interactive                 Reactive
              Environment




               Program
Let’s implement both
  interfaces with...
Enumerable Collections

  interface	
  IEnumerable<out	
  T>
  {
  	
  	
  	
  	
  IEnumerator<T>	
  GetEnumerator();
  }

  interface	
  IEnumerator<out	
  T>
  {
  	
  	
  	
  	
  bool	
  MoveNext();
  	
  	
  	
  	
  T	
  Current	
  {	
  get;	
  }
  }
1
                                            Enumerator
                      GetEnumerator()



                       Current

                                 3
                                                     2
                                        MoveNext()

  Consumer pulls
successive elements                         true/false
from the collection
Dualize Enumerable
      Collections
interface	
  IEnumerable<out	
  T>
{
	
  	
  	
  	
  //	
  void	
  -­‐>	
  enumerator
	
  	
  	
  	
  IEnumerator<T>	
  GetEnumerator();
}

interface	
  IObservable<out	
  T>
{
	
  	
  	
  	
  //	
  observer	
  -­‐>	
  void
	
  	
  	
  	
  IDisposable	
  Subscribe(IObserver<T>	
  o)
}
Dualize Enumerable
                  Collections
interface	
  IEnumerator<out	
  T>
{
	
  	
  	
  	
  bool	
  MoveNext();	
  //	
  void	
  -­‐>	
  bool
	
  	
  	
  	
  T	
  Current	
  {	
  get;	
  }	
  //	
  void	
  -­‐>	
  T
	
  	
  	
  	
  //	
  throws	
  Exception
}

interface	
  IObserver<in	
  T>
{
	
  	
  	
  	
  void	
  OnCompleted(bool	
  done);	
  //	
  bool	
  -­‐>	
  void
	
  	
  	
  	
  T	
  Current	
  {	
  set;	
  }	
  //	
  T	
  -­‐>	
  void
	
  	
  	
  	
  void	
  OnError(Exception	
  ex);	
  //	
  accepts	
  Exception
}
Observable Collections

interface	
  IObservable<out	
  T>
{
	
  	
  	
  	
  IDisposable	
  Subscribe(IObserver<T>	
  o)
}

interface	
  IObserver<in	
  T>
{
	
  	
  	
  	
  void	
  OnCompleted();
	
  	
  	
  	
  void	
  OnNext(T	
  item);
	
  	
  	
  	
  void	
  OnError(Exception	
  ex);
}
1
                                        Observer
                      Subscribe(o)


                      2

                  OnNext(e)
                                                3
                                OnCompleted()


  Producer pushes
successive elements                         X
from the collection
IEnumerable & IEnumerator are
prototypical interfaces for interactive
collections and interactive programs.

IObservable & IObserver are
prototypical interfaces for observable
collections and reactive, asynchronous
& event-based programs.
Iterator




Observer
Iterator / Observer
                 Patterns in Java
interface	
  Iterable<T>	
  {                class	
  Observable	
  {
	
  	
  	
  	
  Iterator<T>	
  iterator();   	
  	
  	
  	
  void	
  addObserver(Observer	
  o);
}
                                             	
  	
  	
  	
  void	
  deleteObserver(Observer	
  o);
                                             	
  	
  	
  	
  void	
  deleteObservers();
                                             	
  	
  	
  	
  int	
  countObservers();
                                             	
  	
  	
  	
  void	
  notifyObservers();
                                             	
  	
  	
  	
  void	
  notifyObservers(Object	
  arg);
                                             	
  	
  	
  	
  void	
  setChanged();
                                             	
  	
  	
  	
  void	
  clearChanged();
                                             	
  	
  	
  	
  boolean	
  hasChanged();
                                             }

interface	
  Iterator<T>	
  {                interface	
  Observer	
  {
	
  	
  	
  	
  T	
  next();                 	
  	
  	
  	
  void	
  update(Observable	
  o,	
  Object	
  arg);
                                             }
	
  	
  	
  	
  boolean	
  hasNext();
	
  	
  	
  	
  void	
  remove();
}
LINQ to Observable
LINQ to Observable

    If you are writing
 LINQ or declarative code
in an interactive program...
LINQ to Observable

    If you are writing
 LINQ or declarative code
in an interactive program...

You already know how to use it!
... the principle we go by is, don't
expect to see a particular
concurrency model put into C#
because there're many different
concurrency model ... it's more
about finding things are common
to to all kinds of concurrency ...

                - Anders Hejlsberg
... the principle we go by is, don't
expect to see a particular
concurrency model put into C#
because there're many different
concurrency model ... it's more
about finding things are common
to to all kinds of concurrency ...

                - Anders Hejlsberg
LINQ to Object
Standard query operators
  Select
  Where
  SelectMany
  ...

Extended query operators
  Zip
  Aggregate
  ...
LINQ to Observable
Standard query operators
  Select
  Where
  SelectMany
  ...

Extended query operators
  Zip
  Throttle
  ...
How to move a ball by
 keyboard (ASDW)?
Imperative Impl.
void	
  OnKeyPress(object	
  sender,	
  KeyPressEventArgs	
  e)
{
	
  	
  	
  	
  if	
  (isPlaying)
	
  	
  	
  	
  {
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (e.KeyChar	
  ==	
  'a'	
  &&	
  ball.Left	
  >	
  0)
	
  	
  	
  	
  	
  	
  	
  	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ball.Left	
  -­‐=	
  5;
	
  	
  	
  	
  	
  	
  	
  	
  }
	
  	
  	
  	
  	
  	
  	
  	
  else	
  if	
  (e.KeyChar	
  ==	
  'w'	
  &&	
  ball.Top	
  >	
  0)
	
  	
  	
  	
  	
  	
  	
  	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ball.Top	
  -­‐=	
  5;
	
  	
  	
  	
  	
  	
  	
  	
  }
	
  	
  	
  	
  	
  	
  	
  	
  else	
  ...
	
  	
  	
  	
  }
	
  	
  	
  	
  else	
  ...
}
Declarative Impl.
//	
  filter	
  the	
  KeyPress	
  events	
  when	
  playing
var	
  keyPress	
  =	
  GetKeyPress().Where(_	
  =>	
  isPlaying);

//	
  filter	
  the	
  events	
  to	
  move	
  left
var	
  moveLeft	
  =	
  from	
  ev	
  in	
  keyPress
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  where	
  ev.EventArgs.KeyChar	
  ==	
  'a'
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  where	
  ball.Left	
  >	
  0
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  select	
  ev;
moveLeft.Subscribe(_	
  =>	
  ball.Left	
  -­‐=	
  5);

//	
  filter	
  the	
  events	
  to	
  move	
  top
var	
  moveTop	
  =	
  from	
  ev	
  in	
  keyPress
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  where	
  ev.EventArgs.KeyChar	
  ==	
  'w'
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  where	
  ball.Top	
  >	
  0
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  select	
  ev;
moveTop.Subscribe(_	
  =>	
  ball.Top	
  -­‐=	
  5);
Mouse drag and draw
var	
  mouseMove	
  =	
  GetMouseMove();
var	
  mouseDiff	
  =	
  mouseMove.Zip(mouseMove.Skip(1),
	
  	
  	
  	
  (prev,	
  curr)	
  =>	
  new
	
  	
  	
  	
  {
	
  	
  	
  	
  	
  	
  	
  	
  PrevPos	
  =	
  new	
  Point(
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  prev.EventArgs.X,	
  prev.EventArgs.Y),
	
  	
  	
  	
  	
  	
  	
  	
  CurrPos	
  =	
  new	
  Point(
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  curr.EventArgs.X,	
  curr.EventArgs.Y)
	
  	
  	
  	
  });

var	
  mouseDrag	
  =	
  from	
  _	
  in	
  GetMouseDown()
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  from	
  diff	
  in	
  mouseDiff.TakeUntil(GetMouseUp())
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  select	
  diff;

mouseDrag.Subscribe(d	
  =>	
  DrawLine(d.PrevPos,	
  d.CurrPos));
Everything in Web is
   Asynchronous

User actions

AJAX requests

Animations

...
Reactive Framework in
      JavaScript
A full featured port for JavaScript
  Easy-to-use conversions from existing DOM,
  XmlHttpRequest, etc
  In a download size of less than 7kb (gzipped)

Bindings for various libraries / frameworks
  jQuery
  MooTools
  Dojo
  ...
Mouse drag and draw
   in JavaScript
var	
  target	
  =	
  $("#paintPad");
var	
  mouseMove	
  =	
  target.toObservable("mousemove");
var	
  mouseDiff	
  =	
  mouseMove.Zip(mouseMove.Skip(1),	
  
	
  	
  	
  	
  function(prev,	
  curr)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  return	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  prevPos:	
  {	
  x:	
  prev.clientX,	
  y:	
  prev.clientY	
  },
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  currPos:	
  {	
  x:	
  curr.clientX,	
  y:	
  curr.clientY	
  }
	
  	
  	
  	
  	
  	
  	
  	
  };
	
  	
  	
  	
  });

var	
  mouseDown	
  =	
  target.toObservable("mousedown");
var	
  mouseUp	
  =	
  target.toObservable("mouseup");
var	
  mouseDrag	
  =	
  mouseDown.SelectMany(function()	
  {
	
  	
  	
  	
  mouseDiff.TakeUntil(mouseUp);
});

mouseDrag.Subscribe(
	
  	
  	
  	
  function(d)	
  {	
  drawLine(d.prevPos,	
  d.currPos);	
  });
Wikipedia lookup
var	
  textBox	
  =	
  $("#searchInput");
var	
  searcher	
  =	
  textBox
	
  	
  	
  	
  .toObservable("keyup")
	
  	
  	
  	
  .Throttle(500)
	
  	
  	
  	
  .Select(function(_)	
  {	
  return	
  textBox.val();	
  })
	
  	
  	
  	
  .Select(function(term)	
  {	
  return	
  queryWikipedia(term);	
  })
	
  	
  	
  	
  .Switch();

searcher.Subscribe(
	
  	
  	
  	
  function(data)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  var	
  results	
  =	
  $("#results");
	
  	
  	
  	
  	
  	
  	
  	
  results.empty();
	
  	
  	
  	
  	
  	
  	
  	
  $.each(data,	
  function(_,	
  value)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  results.append($("<li/>").text(value));
	
  	
  	
  	
  	
  	
  	
  	
  });
	
  	
  	
  	
  },
	
  	
  	
  	
  function(error)	
  {	
  $("#error").html(error);	
  });
Time flies like an arrow
var	
  container	
  =	
  $("#container");
var	
  mouseMove	
  =	
  container.toObservable("mousemove");

for	
  (var	
  i	
  =	
  0;	
  i	
  <	
  text.length;	
  i++)	
  {
	
  	
  	
  	
  (function(i)	
  {

	
  	
  	
  	
  	
  	
  	
  	
  var	
  ele	
  =	
  $("<span/>").text(text.charAt(i));
	
  	
  	
  	
  	
  	
  	
  	
  ele.css({position:	
  "absolute"}).appendTo(container);

	
  	
  	
  	
  	
  	
  	
  	
  mouseMove.Delay(i	
  *	
  100).Subscribe(function	
  (ev)	
  {
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ele.css({
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  left:	
  ev.clientX	
  +	
  i	
  *	
  20	
  +	
  15	
  +	
  "px",
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  top:	
  ev.clientY	
  +	
  "px"
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  });
	
  	
  	
  	
  	
  	
  	
  	
  });

	
  	
  	
  	
  })(i);
Benefits of Rx

Easy to composite and coordinate async
operations

Easy to express the algorithm (code locality)

Easy to be unit tested

...
Rx & Language Features
 Features in C# that Rx uses
   Extension method
   Lambda expression & closure
   Type inference
   LINQ query expression

 Rx has been implemented in ...
   C# & VB
   JavaScript
   F#
Port to other Languages

 Rx can be easily ported to various languages
   Scala
   Ruby
   Python
   modern languages with basic functional features

 Almost impossible to implement Rx in Java
   Cannot extend a type without breaking code
   Missing enough functional features
Resources

Matthew Podwysocki
  http://codebetter.com/blogs/matthew.podwysocki/

Reactive Framework on MSDN DevLabs
  http://msdn.microsoft.com/en-us/devlabs/
  ee794896.aspx

Tomáš Petříček
  http://tomasp.net/
Q&A

响应式编程及框架

  • 1.
    Reactive Programming and Framework Zhao Jie - SNDA - Sep. 2010
  • 2.
    About me / / Jeffrey Zhao / Blog: http://blog.zhaojie.me/ Twitter: @jeffz_cn F#, Scala, JavaScript, Python, .NET, mono... Java (as the language) hater
  • 3.
    What? Fundamentally change theway you think about coordinating and orchestrating asynchronous and event-based programming
  • 4.
    Why? Because the essence of Cloud, Web, Mobile is asynchronous computations
  • 5.
    How? By showing thatasynchronous and event-base computations are just push-based collections
  • 6.
  • 7.
    a := b+ c
  • 8.
    Interactive Reactive Environment Program
  • 9.
    Let’s implement both interfaces with...
  • 11.
    Enumerable Collections interface  IEnumerable<out  T> {        IEnumerator<T>  GetEnumerator(); } interface  IEnumerator<out  T> {        bool  MoveNext();        T  Current  {  get;  } }
  • 12.
    1 Enumerator GetEnumerator() Current 3 2 MoveNext() Consumer pulls successive elements true/false from the collection
  • 13.
    Dualize Enumerable Collections interface  IEnumerable<out  T> {        //  void  -­‐>  enumerator        IEnumerator<T>  GetEnumerator(); } interface  IObservable<out  T> {        //  observer  -­‐>  void        IDisposable  Subscribe(IObserver<T>  o) }
  • 14.
    Dualize Enumerable Collections interface  IEnumerator<out  T> {        bool  MoveNext();  //  void  -­‐>  bool        T  Current  {  get;  }  //  void  -­‐>  T        //  throws  Exception } interface  IObserver<in  T> {        void  OnCompleted(bool  done);  //  bool  -­‐>  void        T  Current  {  set;  }  //  T  -­‐>  void        void  OnError(Exception  ex);  //  accepts  Exception }
  • 15.
    Observable Collections interface  IObservable<out  T> {        IDisposable  Subscribe(IObserver<T>  o) } interface  IObserver<in  T> {        void  OnCompleted();        void  OnNext(T  item);        void  OnError(Exception  ex); }
  • 16.
    1 Observer Subscribe(o) 2 OnNext(e) 3 OnCompleted() Producer pushes successive elements X from the collection
  • 17.
    IEnumerable & IEnumeratorare prototypical interfaces for interactive collections and interactive programs. IObservable & IObserver are prototypical interfaces for observable collections and reactive, asynchronous & event-based programs.
  • 18.
  • 19.
    Iterator / Observer Patterns in Java interface  Iterable<T>  { class  Observable  {        Iterator<T>  iterator();        void  addObserver(Observer  o); }        void  deleteObserver(Observer  o);        void  deleteObservers();        int  countObservers();        void  notifyObservers();        void  notifyObservers(Object  arg);        void  setChanged();        void  clearChanged();        boolean  hasChanged(); } interface  Iterator<T>  { interface  Observer  {        T  next();        void  update(Observable  o,  Object  arg); }        boolean  hasNext();        void  remove(); }
  • 20.
  • 21.
    LINQ to Observable If you are writing LINQ or declarative code in an interactive program...
  • 22.
    LINQ to Observable If you are writing LINQ or declarative code in an interactive program... You already know how to use it!
  • 23.
    ... the principlewe go by is, don't expect to see a particular concurrency model put into C# because there're many different concurrency model ... it's more about finding things are common to to all kinds of concurrency ... - Anders Hejlsberg
  • 24.
    ... the principlewe go by is, don't expect to see a particular concurrency model put into C# because there're many different concurrency model ... it's more about finding things are common to to all kinds of concurrency ... - Anders Hejlsberg
  • 25.
    LINQ to Object Standardquery operators Select Where SelectMany ... Extended query operators Zip Aggregate ...
  • 26.
    LINQ to Observable Standardquery operators Select Where SelectMany ... Extended query operators Zip Throttle ...
  • 27.
    How to movea ball by keyboard (ASDW)?
  • 28.
    Imperative Impl. void  OnKeyPress(object  sender,  KeyPressEventArgs  e) {        if  (isPlaying)        {                if  (e.KeyChar  ==  'a'  &&  ball.Left  >  0)                {                        ball.Left  -­‐=  5;                }                else  if  (e.KeyChar  ==  'w'  &&  ball.Top  >  0)                {                        ball.Top  -­‐=  5;                }                else  ...        }        else  ... }
  • 29.
    Declarative Impl. //  filter  the  KeyPress  events  when  playing var  keyPress  =  GetKeyPress().Where(_  =>  isPlaying); //  filter  the  events  to  move  left var  moveLeft  =  from  ev  in  keyPress                              where  ev.EventArgs.KeyChar  ==  'a'                              where  ball.Left  >  0                              select  ev; moveLeft.Subscribe(_  =>  ball.Left  -­‐=  5); //  filter  the  events  to  move  top var  moveTop  =  from  ev  in  keyPress                            where  ev.EventArgs.KeyChar  ==  'w'                            where  ball.Top  >  0                            select  ev; moveTop.Subscribe(_  =>  ball.Top  -­‐=  5);
  • 30.
  • 31.
    var  mouseMove  =  GetMouseMove(); var  mouseDiff  =  mouseMove.Zip(mouseMove.Skip(1),        (prev,  curr)  =>  new        {                PrevPos  =  new  Point(                        prev.EventArgs.X,  prev.EventArgs.Y),                CurrPos  =  new  Point(                        curr.EventArgs.X,  curr.EventArgs.Y)        }); var  mouseDrag  =  from  _  in  GetMouseDown()                                from  diff  in  mouseDiff.TakeUntil(GetMouseUp())                                select  diff; mouseDrag.Subscribe(d  =>  DrawLine(d.PrevPos,  d.CurrPos));
  • 32.
    Everything in Webis Asynchronous User actions AJAX requests Animations ...
  • 33.
    Reactive Framework in JavaScript A full featured port for JavaScript Easy-to-use conversions from existing DOM, XmlHttpRequest, etc In a download size of less than 7kb (gzipped) Bindings for various libraries / frameworks jQuery MooTools Dojo ...
  • 34.
    Mouse drag anddraw in JavaScript
  • 35.
    var  target  =  $("#paintPad"); var  mouseMove  =  target.toObservable("mousemove"); var  mouseDiff  =  mouseMove.Zip(mouseMove.Skip(1),          function(prev,  curr)  {                return  {                        prevPos:  {  x:  prev.clientX,  y:  prev.clientY  },                        currPos:  {  x:  curr.clientX,  y:  curr.clientY  }                };        }); var  mouseDown  =  target.toObservable("mousedown"); var  mouseUp  =  target.toObservable("mouseup"); var  mouseDrag  =  mouseDown.SelectMany(function()  {        mouseDiff.TakeUntil(mouseUp); }); mouseDrag.Subscribe(        function(d)  {  drawLine(d.prevPos,  d.currPos);  });
  • 36.
  • 37.
    var  textBox  =  $("#searchInput"); var  searcher  =  textBox        .toObservable("keyup")        .Throttle(500)        .Select(function(_)  {  return  textBox.val();  })        .Select(function(term)  {  return  queryWikipedia(term);  })        .Switch(); searcher.Subscribe(        function(data)  {                var  results  =  $("#results");                results.empty();                $.each(data,  function(_,  value)  {                        results.append($("<li/>").text(value));                });        },        function(error)  {  $("#error").html(error);  });
  • 38.
  • 39.
    var  container  =  $("#container"); var  mouseMove  =  container.toObservable("mousemove"); for  (var  i  =  0;  i  <  text.length;  i++)  {        (function(i)  {                var  ele  =  $("<span/>").text(text.charAt(i));                ele.css({position:  "absolute"}).appendTo(container);                mouseMove.Delay(i  *  100).Subscribe(function  (ev)  {                        ele.css({                                left:  ev.clientX  +  i  *  20  +  15  +  "px",                                top:  ev.clientY  +  "px"                        });                });        })(i);
  • 40.
    Benefits of Rx Easyto composite and coordinate async operations Easy to express the algorithm (code locality) Easy to be unit tested ...
  • 41.
    Rx & LanguageFeatures Features in C# that Rx uses Extension method Lambda expression & closure Type inference LINQ query expression Rx has been implemented in ... C# & VB JavaScript F#
  • 42.
    Port to otherLanguages Rx can be easily ported to various languages Scala Ruby Python modern languages with basic functional features Almost impossible to implement Rx in Java Cannot extend a type without breaking code Missing enough functional features
  • 43.
    Resources Matthew Podwysocki http://codebetter.com/blogs/matthew.podwysocki/ Reactive Framework on MSDN DevLabs http://msdn.microsoft.com/en-us/devlabs/ ee794896.aspx Tomáš Petříček http://tomasp.net/
  • 44.