ninjinkun's diary

ninjinkunの日記

【翻訳】あなたが求めていたリアクティブプログラミング入門




Rx.Observable.prototype.flatMapLatest(selector, [thisArg])

Projects each element of an observable sequence into a new sequence of observable sequences by incorporating the element's index and then transforms an observable sequence of observable sequences into an observable sequence producing values only from the most recent observable sequence.
ObservableObservableObservableObservableObservableObservable



2FRP使Futurice使

FRPFRP

" (FRP) ?"


Wikipedia StackoverflowReactive Manifesto"Rx = Observables + LINQ + Schedulers" "" MV*FRP


FRP ( FRP is programming with asynchronous data streams)


FRPTwitterlisten

使使mergefiltermap

FRP

Click event stream
() "" 3"" 

3'' "listening"  subscribing observerobservesubject ( "observable") Observer Design Pattern

ASCII使使
--a---b-c---d---X---|->

a, b, c, d are emitted values
X is an error
| is the 'completed' signal
---> is the timeline

退

FRPmapfilterscan使clickStream.map(f)FRPclickStream.map(f).scan(g)
  clickStream: ---c----c--c----c------c-->
               vvvvv map(c becomes 1) vvvv
               ---1----1--1----1------1-->
               vvvvvvvvv scan(+) vvvvvvvvv
counterStream: ---1----2--3----4------5-->

map(f)f () 1scan(g) x = g(accumulated, current) gcounterStream

FRP""  (2) 

FRP4

Multiple clicks stream
250 (buffer(stream.throttle(250ms))FRP) map()mapfilter(x >= 2)13subscribe ("listen")

API使

"FRP"


FRPFRP使

WebUI10Web


FRP


FRP

JavaScriptRxJSJavaScriptRx*   (.NET, JavaScala, ClojureJavaScript, Ruby, PythonC++Objective-C/Cocoa, Groovy)使

"Who to follow" 


TwitterUI

Twitter Who to follow suggestions box



API3

"" 33

'x'




TwitterAPI使使GithubUIGithub API

 http://jsfiddle.net/staltz/8jFJH/48/ 


FRP FRP"API3" (1)  (2)  (3) 

1111
--a------|->

Where a is the string 'https://api.github.com/users'

URLURL

Rx* "Observable" 鹿
var requestStream = Rx.Observable.returnValue('https://api.github.com/users');

subscribing

jQuery Ajax callback使FRP
requestStream.subscribe(function(requestUrl) {
  // execute the request
  var responseStream = Rx.Observable.create(function (observer) {
    jQuery.getJSON(requestUrl)
    .done(function(response) { observer.onNext(response); })
    .fail(function(jqXHR, status, error) { observer.onError(error); })
    .always(function() { observer.onCompleted(); });
  });

  responseStream.subscribe(function(response) {
    // do something with the response
  });
}

Rx.Observable.create() observer ( "subscriber")  (onNext())  (onError()) jQuery Ajax PromisePromiseObservable

         

Amazed


ObservablePromise++Rxvar stream = Rx.Observable.fromPromise(promise)PromiseObservableObservablePromises/A+PromiseObservableFRPpromise

FRPPromisePromiseFRP

subscribe()使responseStreamrequestStreamFRP

map(f)stream Af()stream BURL () Promisemap
var responseMetastream = requestStream
  .map(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

URLpromisemap

Response metastream
JSON'Promise'JSONFlatmapmap()"" "" FlatmapFRP
var responseStream = requestStream
  .flatMap(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

Response stream

requestStream:  --a-----b--c------------|->
responseStream: -----A--------B-----C---|->

(lowercase is a request, uppercase is its response)


responseStream.subscribe(function(response) {
  // render `response` to the DOM however you wish
});


var requestStream = Rx.Observable.returnValue('https://api.github.com/users');

var responseStream = requestStream
  .flatMap(function(requestUrl) {
    return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl));
  });

responseStream.subscribe(function(response) {
  // render `response` to the DOM however you wish
});


JSON100API3使97

URL2 (: ) RxJSObservable
var refreshButton = document.querySelector('.refresh');
var refreshClickStream = Rx.Observable.fromEvent(refreshButton, 'click');

API URLURLmapAPImap
var requestStream = refreshClickStream
  .map(function() {
    var randomOffset = Math.floor(Math.random()*500);
    return 'https://api.github.com/users?since=' + randomOffset;
  });

Web


var requestOnRefreshStream = refreshClickStream
  .map(function() {
    var randomOffset = Math.floor(Math.random()*500);
    return 'https://api.github.com/users?since=' + randomOffset;
  });

var startupRequestStream = Rx.Observable.returnValue('https://api.github.com/users');

21merge()
stream A: ---a--------e-----o----->
stream B: -----B---C-----D-------->
          vvvvvvvvv merge vvvvvvvvv
          ---a-B---C--e--D--o----->


var requestOnRefreshStream = refreshClickStream
  .map(function() {
    var randomOffset = Math.floor(Math.random()*500);
    return 'https://api.github.com/users?since=' + randomOffset;
  });

var startupRequestStream = Rx.Observable.returnValue('https://api.github.com/users');

var requestStream = Rx.Observable.merge(
  requestOnRefreshStream, startupRequestStream
);


var requestStream = refreshClickStream
  .map(function() {
    var randomOffset = Math.floor(Math.random()*500);
    return 'https://api.github.com/users?since=' + randomOffset;
  })
  .merge(Rx.Observable.returnValue('https://api.github.com/users'));


var requestStream = refreshClickStream
  .map(function() {
    var randomOffset = Math.floor(Math.random()*500);
    return 'https://api.github.com/users?since=' + randomOffset;
  })
  .startWith('https://api.github.com/users');

startWith() startWith(x)xDRYAPIstartWith()refreshClickStream""
var requestStream = refreshClickStream.startWith('startup click')
  .map(function() {
    var randomOffset = Math.floor(Math.random()*500);
    return 'https://api.github.com/users?since=' + randomOffset;
  });

"" startWith()

3


responseStreamsubscribe()UI''3UI
refreshClickStream.subscribe(function() {
  // clear the 3 suggestion DOM elements
});

DOM (1responseStream.subscribe())2subscriberFRP

       

Mantra
JSON3 #1 
var suggestion1Stream = responseStream
  .map(function(listUsers) {
    // get one random user from the list
    return listUsers[Math.floor(Math.random()*listUsers.length)];
  });

suggestion2Streamsuggestion3Streamsuggestion1StreamDRY

responseStreamsubscribe()
suggestion1Stream.subscribe(function(suggestion) {
  // render the 1st suggestion to the DOM
});

"" 'null'mapsuggestion1Stream
var suggestion1Stream = responseStream
  .map(function(listUsers) {
    // get one random user from the list
    return listUsers[Math.floor(Math.random()*listUsers.length)];
  })
  .merge(
    refreshClickStream.map(function(){ return null; })
  );

nullUI
suggestion1Stream.subscribe(function(suggestion) {
  if (suggestion === null) {
    // hide the first suggestion DOM element
  }
  else {
    // show the first suggestion DOM element
    // and render the data
  }
});


refreshClickStream: ----------o--------o---->
     requestStream: -r--------r--------r---->
    responseStream: ----R---------R------R-->
 suggestion1Stream: ----s-----N---s----N-s-->
 suggestion2Stream: ----q-----N---q----N-q-->
 suggestion3Stream: ----t-----N---t----N-t-->

Nnull

startWith(null)
var suggestion1Stream = responseStream
  .map(function(listUsers) {
    // get one random user from the list
    return listUsers[Math.floor(Math.random()*listUsers.length)];
  })
  .merge(
    refreshClickStream.map(function(){ return null; })
  )
  .startWith(null);


refreshClickStream: ----------o---------o---->
     requestStream: -r--------r---------r---->
    responseStream: ----R----------R------R-->
 suggestion1Stream: -N--s-----N----s----N-s-->
 suggestion2Stream: -N--q-----N----q----N-q-->
 suggestion3Stream: -N--t-----N----t----N-t-->

使


'x'
var close1Button = document.querySelector('.close1');
var close1ClickStream = Rx.Observable.fromEvent(close1Button, 'click');
// and the same for close2Button and close3Button

var requestStream = refreshClickStream.startWith('startup click')
  .merge(close1ClickStream) // we added this
  .map(function() {
    var randomOffset = Math.floor(Math.random()*500);
    return 'https://api.github.com/users?since=' + randomOffset;
  });

1API1003使

'close1'1responseStream使
    requestStream: --r--------------->
   responseStream: ------R----------->
close1ClickStream: ------------c----->
suggestion1Stream: ------s-----s----->

Rx*combineLatest2ABcombineLatestab2f1c = f(x,y)
stream A: --a-----------e--------i-------->
stream B: -----b----c--------d-------q---->
          vvvvvvvv combineLatest(f) vvvvvvv
          ----AB---AC--EC---ED--ID--IQ---->

where f is the uppercase function

combineLatest()close1ClickStreamresponseStreamclose 1suggestion1StreamcombineLatest()responseStreamcombineLatest()'close 1'suggestion1Stream
var suggestion1Stream = close1ClickStream
  .combineLatest(responseStream,
    function(click, listUsers) {
      return listUsers[Math.floor(Math.random()*listUsers.length)];
    }
  )
  .merge(
    refreshClickStream.map(function(){ return null; })
  )
  .startWith(null);

1combineLatest()2使combineLatest()ASCII1a2b

'close 1'



var refreshButton = document.querySelector('.refresh');
var refreshClickStream = Rx.Observable.fromEvent(refreshButton, 'click');

var closeButton1 = document.querySelector('.close1');
var close1ClickStream = Rx.Observable.fromEvent(closeButton1, 'click');
// and the same logic for close2 and close3

var requestStream = refreshClickStream.startWith('startup click')
  .map(function() {
    var randomOffset = Math.floor(Math.random()*500);
    return 'https://api.github.com/users?since=' + randomOffset;
  });

var responseStream = requestStream
  .flatMap(function (requestUrl) {
    return Rx.Observable.fromPromise($.ajax({url: requestUrl}));
  });

var suggestion1Stream = close1ClickStream.startWith('startup click')
  .combineLatest(responseStream,
    function(click, listUsers) {
      return listUsers[Math.floor(Math.random()*listUsers.length)];
    }
  )
  .merge(
    refreshClickStream.map(function(){ return null; })
  )
  .startWith(null);
// and the same logic for suggestion2Stream and suggestion3Stream

suggestion1Stream.subscribe(function(suggestion) {
  if (suggestion === null) {
    // hide the first suggestion DOM element
  }
  else {
    // show the first suggestion DOM element
    // and render the data
  }
});

 http://jsfiddle.net/staltz/8jFJH/48/

FRPsuggestion1Stream'close 1'1null

ifforwhileJavaScriptsubscribe()ifelsefilter()使 ()FRPmapfilterscanmergecombineLatest, startWith


Rx*Observable使RxJava

RxCold vs Hot ObservablesRx*

(FRP)RxRxBacon.jsElmJavaScript+HTML+CSSFRP

FRPFRPRxJavaNetflixAPIFRP使

Tweet

         

staltz commented on Jul 1


[1][2]

 "FRP"  "RP" [3][4][5]