Download free for 30 days
Sign in
Upload
Language (EN)
Support
Business
Mobile
Social Media
Marketing
Technology
Art & Photos
Career
Design
Education
Presentations & Public Speaking
Government & Nonprofit
Healthcare
Internet
Law
Leadership & Management
Automotive
Engineering
Software
Recruiting & HR
Retail
Sales
Services
Science
Small Business & Entrepreneurship
Food
Environment
Economy & Finance
Data & Analytics
Investor Relations
Sports
Spiritual
News & Politics
Travel
Self Improvement
Real Estate
Entertainment & Humor
Health & Medicine
Devices & Hardware
Lifestyle
Change Language
Language
English
Español
Português
Français
Deutsche
Cancel
Save
EN
Uploaded by
rf0444
1,607 views
FRP in Practice
Read more
6
Save
Share
Embed
Embed presentation
Download
Download to read offline
1
/ 57
2
/ 57
3
/ 57
4
/ 57
5
/ 57
6
/ 57
7
/ 57
8
/ 57
9
/ 57
10
/ 57
11
/ 57
12
/ 57
13
/ 57
14
/ 57
15
/ 57
16
/ 57
17
/ 57
18
/ 57
19
/ 57
20
/ 57
21
/ 57
22
/ 57
23
/ 57
24
/ 57
25
/ 57
26
/ 57
27
/ 57
28
/ 57
29
/ 57
30
/ 57
31
/ 57
32
/ 57
33
/ 57
34
/ 57
35
/ 57
36
/ 57
37
/ 57
38
/ 57
39
/ 57
40
/ 57
41
/ 57
42
/ 57
43
/ 57
44
/ 57
45
/ 57
46
/ 57
47
/ 57
48
/ 57
49
/ 57
50
/ 57
51
/ 57
52
/ 57
53
/ 57
54
/ 57
55
/ 57
56
/ 57
57
/ 57
More Related Content
PDF
Sencha Touchをさわってみた
by
Tomonori Ohba
PDF
20150530 pgunconf-pgbench-semi-structured-benchmark
by
Toshi Harada
PDF
SWF
by
rf0444
PDF
モナドをつくろう
by
dico_leque
PDF
Knockout.js を利用したインタラクティブ web アプリケーション開発
by
Daizen Ikehara
KEY
Knockout
by
Kazuhiro Eguchi
PDF
enchant.js勉強会
by
Hiroaki Murayama
PPTX
2時間で学ぶjQuery
by
Shumpei Shiraishi
Sencha Touchをさわってみた
by
Tomonori Ohba
20150530 pgunconf-pgbench-semi-structured-benchmark
by
Toshi Harada
SWF
by
rf0444
モナドをつくろう
by
dico_leque
Knockout.js を利用したインタラクティブ web アプリケーション開発
by
Daizen Ikehara
Knockout
by
Kazuhiro Eguchi
enchant.js勉強会
by
Hiroaki Murayama
2時間で学ぶjQuery
by
Shumpei Shiraishi
Similar to FRP in Practice
PDF
Chrome Developer Toolsを使いこなそう!
by
yoshikawa_t
PDF
DOMイベントの基礎から深淵まで
by
Masayuki Nakano
PPT
20130924 Picomon CRH勉強会
by
Yukihiro Kitazawa
PDF
JavaScript Basic 02 jQuery
by
Yossy Taka
PDF
Reflexの紹介
by
Rie Nakau
KEY
はじめてのCouch db
by
Eiji Kuroda
PDF
Knockout_エンジニア勉強会20131120
by
エンジニア勉強会 エスキュービズム
PDF
Xamarin で ReactiveUI を使ってみた
by
Hironov OKUYAMA
PDF
Start FRP
by
rf0444
PDF
Livesense tech night immutable-js at a glance
by
Yuta Shimakawa
PDF
Spine入門
by
AdvancedTechNight
PDF
Knockout handson
by
Go Tanaka
PDF
実践Knockout
by
Kazuhiro Eguchi
PPTX
Flight入門
by
Toshihiro Yagi
PDF
Sansan様 登壇資料
by
Daisuke Nagata
PPTX
MVVM入門
by
Kazutoshi Urabe
PPTX
UniRxことはじめ
by
Shoichi Yasui
PPTX
Rxに入門しようとしている
by
onotchi_
PDF
はじめよう Backbone.js
by
Hiroki Toyokawa
PDF
エンジニア勉強会_DECIDE
by
エンジニア勉強会 エスキュービズム
Chrome Developer Toolsを使いこなそう!
by
yoshikawa_t
DOMイベントの基礎から深淵まで
by
Masayuki Nakano
20130924 Picomon CRH勉強会
by
Yukihiro Kitazawa
JavaScript Basic 02 jQuery
by
Yossy Taka
Reflexの紹介
by
Rie Nakau
はじめてのCouch db
by
Eiji Kuroda
Knockout_エンジニア勉強会20131120
by
エンジニア勉強会 エスキュービズム
Xamarin で ReactiveUI を使ってみた
by
Hironov OKUYAMA
Start FRP
by
rf0444
Livesense tech night immutable-js at a glance
by
Yuta Shimakawa
Spine入門
by
AdvancedTechNight
Knockout handson
by
Go Tanaka
実践Knockout
by
Kazuhiro Eguchi
Flight入門
by
Toshihiro Yagi
Sansan様 登壇資料
by
Daisuke Nagata
MVVM入門
by
Kazutoshi Urabe
UniRxことはじめ
by
Shoichi Yasui
Rxに入門しようとしている
by
onotchi_
はじめよう Backbone.js
by
Hiroki Toyokawa
エンジニア勉強会_DECIDE
by
エンジニア勉強会 エスキュービズム
More from rf0444
PDF
PFDS 11.2.2
by
rf0444
PDF
PFDS 10.1.2
by
rf0444
PDF
PFDS 9.3.2
by
rf0444
PDF
PFDS 9.3.1
by
rf0444
PDF
PFDS 8.4.1
by
rf0444
PDF
PFDS 7.4
by
rf0444
PDF
Tapl 5
by
rf0444
PDF
Haskellday rf
by
rf0444
PDF
PFDS 6.4.3
by
rf0444
PFDS 11.2.2
by
rf0444
PFDS 10.1.2
by
rf0444
PFDS 9.3.2
by
rf0444
PFDS 9.3.1
by
rf0444
PFDS 8.4.1
by
rf0444
PFDS 7.4
by
rf0444
Tapl 5
by
rf0444
Haskellday rf
by
rf0444
PFDS 6.4.3
by
rf0444
FRP in Practice
1.
Functional Reactive Programming 実践編 ∼
画面作成、リクエスト処理 ∼ @rf0444
2.
利用ライブラリ • Bacon.js • https://github.com/raimohanska/bacon.js •
jQuery
3.
おしながき • EventStream と
Property • 画面を作る • リクエスト処理
4.
EventStream と Property
5.
EventStream • 発生するイベントの列 を表す •
クリックされた、など 時間 値
6.
Property • 時間によって変化する値 を表す •
View に表示する値、最後に返ってきたレスポンス など 時間 値
7.
EventStream / Property •
EventStream#merge(EventStream) • 2つの EventStream をくっつけた EventStream を作る。 時間 値 時間 値 時間 値 e1 e2 e1.merge(e2)
8.
EventStream / Property •
EventStream#toProperty([initVal]) • EventStream に 値が流れてくる タイミングで、値が変化する Property を作る。 • 引数に初期値を指定できる。 (なしも可) 時間 値 時間 値 v0 es es.toProperty(v0)
9.
EventStream / Property •
Property#changes() • Property の値が変化した タイミングで、変化後の 値が流れる EventStream を作る。 • 初期値は流れない 時間 値 p.changes() 時間 値 p
10.
EventStream / Property •
Property#sampledBy(EventStream) • EventStream に値が流れた時点 の Property の値が流れる EventStream を作る。 時間 値 時間 値 時間 値 p es p.sampledBy(es)
11.
画面を作る
12.
設計方針 • 出来るだけ副作用を排除したい。 • Callback
内処理を、単純な副作用だけにしたい。
13.
例: Click Counter クリックすると 増える
14.
例: Click Counter $(function()
{ var constant = function(x) { return function() { return x; }; }; var mkButton = function(conf) { var el = $('<button />').text(conf.text); return { el: el, streams: { clicked: el.asEventStream('click') } }; }; var mkText = function(conf) { var el = $('<span />'); conf.text.assign(function(text) { el.text(text); }); return { el: el }; }; var button = mkButton({ text: 'click' }); var text = mkText({ text: button.streams.clicked .map(constant(1)) .scan(0, function(a, b) { return a + b; }), }); $('body').append(button.el).append(' ').append(text.el); });
15.
例: Click Counter $(function()
{ var constant = function(x) { return function() { return x; }; }; var mkButton = function(conf) { var el = $('<button />').text(conf.text); return { el: el, streams: { clicked: el.asEventStream('click') } }; }; var mkText = function(conf) { var el = $('<span />'); conf.text.assign(function(text) { el.text(text); }); return { el: el }; }; var button = mkButton({ text: 'click' }); var text = mkText({ text: button.streams.clicked .map(constant(1)) .scan(0, function(a, b) { return a + b; }), }); $('body').append(button.el).append(' ').append(text.el); }); ボタン右のテキストの値 (時間によって変化する)
16.
例: Click Counter $(function()
{ var constant = function(x) { return function() { return x; }; }; var mkButton = function(conf) { var el = $('<button />').text(conf.text); return { el: el, streams: { clicked: el.asEventStream('click') } }; }; var mkText = function(conf) { var el = $('<span />'); conf.text.assign(function(text) { el.text(text); }); return { el: el }; }; var button = mkButton({ text: 'click' }); var text = mkText({ text: button.streams.clicked .map(constant(1)) .scan(0, function(a, b) { return a + b; }), }); $('body').append(button.el).append(' ').append(text.el); }); クリックされたら 1 が 流れてくる EventStream
17.
例: Click Counter $(function()
{ var constant = function(x) { return function() { return x; }; }; var mkButton = function(conf) { var el = $('<button />').text(conf.text); return { el: el, streams: { clicked: el.asEventStream('click') } }; }; var mkText = function(conf) { var el = $('<span />'); conf.text.assign(function(text) { el.text(text); }); return { el: el }; }; var button = mkButton({ text: 'click' }); var text = mkText({ text: button.streams.clicked .map(constant(1)) .scan(0, function(a, b) { return a + b; }), }); $('body').append(button.el).append(' ').append(text.el); }); クリックされたら 1 が 流れてくる EventStream 0 から順に、足して畳み込んでいく (初期値 0 の Property ができる)
18.
例: Click Counter $(function()
{ var constant = function(x) { return function() { return x; }; }; var mkButton = function(conf) { var el = $('<button />').text(conf.text); return { el: el, streams: { clicked: el.asEventStream('click') } }; }; var mkText = function(conf) { var el = $('<span />'); conf.text.assign(function(text) { el.text(text); }); return { el: el }; }; var button = mkButton({ text: 'click' }); var text = mkText({ text: button.streams.clicked .map(constant(1)) .scan(0, function(a, b) { return a + b; }), }); $('body').append(button.el).append(' ').append(text.el); }); 副作用 (値変化時の処理登録、 テキストの中身を変更) 副作用 (DOM 要素登録)
19.
例: Counting Button クリックすると増える
20.
例: Counting Button クリックすると増える Property
を作るために、 作成後の button の EventStream が必要
21.
例: Counting Button クリックすると増える Property
を作るために、 作成後の button の EventStream が必要 EventStream -> Property な 関数を渡すようにしてみる
22.
例: Counting Button $(function()
{ var constant = function(x) { return function() { return x; }; }; var mkButton = function(conf) { var el = $('<button />'); var streams = { clicked: el.asEventStream('click') }; var properties = conf.f(streams); properties.text.assign(function(text) { el.text(text); }); return { el: el }; }; var button = mkButton({ f: function(streams) { return { text: streams.clicked .map(constant(1)) .scan(0, function(a, b) { return a + b; }), }; }, }); $('body').append(button.el); });
23.
例: Counting Button $(function()
{ var constant = function(x) { return function() { return x; }; }; var mkButton = function(conf) { var el = $('<button />'); var streams = { clicked: el.asEventStream('click') }; var properties = conf.f(streams); properties.text.assign(function(text) { el.text(text); }); return { el: el }; }; var button = mkButton({ f: function(streams) { return { text: streams.clicked .map(constant(1)) .scan(0, function(a, b) { return a + b; }), }; }, }); $('body').append(button.el); }); EventStream -> Property な関数
24.
例: Counting Button $(function()
{ var constant = function(x) { return function() { return x; }; }; var mkButton = function(conf) { var el = $('<button />'); var streams = { clicked: el.asEventStream('click') }; var properties = conf.f(streams); properties.text.assign(function(text) { el.text(text); }); return { el: el }; }; var button = mkButton({ f: function(streams) { return { text: streams.clicked .map(constant(1)) .scan(0, function(a, b) { return a + b; }), }; }, }); $('body').append(button.el); }); 渡された EventStream を 畳み込んで、Propertyを作る
25.
例: Counting Button $(function()
{ var constant = function(x) { return function() { return x; }; }; var mkButton = function(conf) { var el = $('<button />'); var streams = { clicked: el.asEventStream('click') }; var properties = conf.f(streams); properties.text.assign(function(text) { el.text(text); }); return { el: el }; }; var button = mkButton({ f: function(streams) { return { text: streams.clicked .map(constant(1)) .scan(0, function(a, b) { return a + b; }), }; }, }); $('body').append(button.el); }); 先に EventStream を 作っておいて、
26.
例: Counting Button $(function()
{ var constant = function(x) { return function() { return x; }; }; var mkButton = function(conf) { var el = $('<button />'); var streams = { clicked: el.asEventStream('click') }; var properties = conf.f(streams); properties.text.assign(function(text) { el.text(text); }); return { el: el }; }; var button = mkButton({ f: function(streams) { return { text: streams.clicked .map(constant(1)) .scan(0, function(a, b) { return a + b; }), }; }, }); $('body').append(button.el); }); 渡された関数に適用 して、Property を得る 先に EventStream を 作っておいて、
27.
$(function() { var
constant = function(x) { return function() { return x; }; }; var mkButton = function(conf) { var el = $('<button />'); var streams = { clicked: el.asEventStream('click') }; var properties = conf.f(streams); properties.text.assign(function(text) { el.text(text); }); return { el: el }; }; var button = mkButton({ f: function(streams) { return { text: streams.clicked .map(constant(1)) .scan(0, function(a, b) { return a + b; }), }; }, }); $('body').append(button.el); }); 例: Counting Button 副作用 (値変化時の処理登録、 テキストの中身を変更) 副作用 (DOM 要素登録)
28.
例: Cross Counting
Button クリックすると 反対側が増える
29.
例: Cross Counting
Button クリックすると 反対側が増える Property を作るために、 別の button の EventStream が必要 (相互に要求)
30.
例: Cross Counting
Button クリックすると 反対側が増える Property を作るために、 別の button の EventStream が必要 (相互に要求) Bus を使い、 一旦 EventStream として渡しておき、 button を作るときに Bus につなぐ
31.
例: Cross Counting
Button $(function() { var constant = function(x) { return function() { return x; }; }; var mkButton = { streams: function() { return { clicked: new Bacon.Bus() }; }, create: function(conf) { var el = $('<button />'); conf.properties.text.assign(function(text) { el.text(text); }); conf.streams.clicked.plug(el.asEventStream('click')); return { el: el }; }, }; var streams1 = mkButton.streams(); var streams2 = mkButton.streams(); var logic = function(s) { return s.clicked.map(constant(1)).scan(0, function(a, b) { return a + b; }); }; var button1 = mkButton.create({ properties: { text: logic(streams2) }, streams: streams1, }); var button2 = mkButton.create({ properties: { text: logic(streams1) }, streams: streams2, }); $('body').append(button1.el).append(' ').append(button2.el); });
32.
例: Cross Counting
Button $(function() { var constant = function(x) { return function() { return x; }; }; var mkButton = { streams: function() { return { clicked: new Bacon.Bus() }; }, create: function(conf) { var el = $('<button />'); conf.properties.text.assign(function(text) { el.text(text); }); conf.streams.clicked.plug(el.asEventStream('click')); return { el: el }; }, }; var streams1 = mkButton.streams(); var streams2 = mkButton.streams(); var logic = function(s) { return s.clicked.map(constant(1)).scan(0, function(a, b) { return a + b; }); }; var button1 = mkButton.create({ properties: { text: logic(streams2) }, streams: streams1, }); var button2 = mkButton.create({ properties: { text: logic(streams1) }, streams: streams2, }); $('body').append(button1.el).append(' ').append(button2.el); }); button から出る EventStream を Bus として 取得できるようにしておく
33.
例: Cross Counting
Button $(function() { var constant = function(x) { return function() { return x; }; }; var mkButton = { streams: function() { return { clicked: new Bacon.Bus() }; }, create: function(conf) { var el = $('<button />'); conf.properties.text.assign(function(text) { el.text(text); }); conf.streams.clicked.plug(el.asEventStream('click')); return { el: el }; }, }; var streams1 = mkButton.streams(); var streams2 = mkButton.streams(); var logic = function(s) { return s.clicked.map(constant(1)).scan(0, function(a, b) { return a + b; }); }; var button1 = mkButton.create({ properties: { text: logic(streams2) }, streams: streams1, }); var button2 = mkButton.create({ properties: { text: logic(streams1) }, streams: streams2, }); $('body').append(button1.el).append(' ').append(button2.el); }); 先に EventStream だけ 取得しておいて、 button から出る EventStream を Bus として 取得できるようにしておく
34.
例: Cross Counting
Button $(function() { var constant = function(x) { return function() { return x; }; }; var mkButton = { streams: function() { return { clicked: new Bacon.Bus() }; }, create: function(conf) { var el = $('<button />'); conf.properties.text.assign(function(text) { el.text(text); }); conf.streams.clicked.plug(el.asEventStream('click')); return { el: el }; }, }; var streams1 = mkButton.streams(); var streams2 = mkButton.streams(); var logic = function(s) { return s.clicked.map(constant(1)).scan(0, function(a, b) { return a + b; }); }; var button1 = mkButton.create({ properties: { text: logic(streams2) }, streams: streams1, }); var button2 = mkButton.create({ properties: { text: logic(streams1) }, streams: streams2, }); $('body').append(button1.el).append(' ').append(button2.el); }); 先に EventStream だけ 取得しておいて、 EventStream から Property を作成 button から出る EventStream を Bus として 取得できるようにしておく
35.
例: Cross Counting
Button $(function() { var constant = function(x) { return function() { return x; }; }; var mkButton = { streams: function() { return { clicked: new Bacon.Bus() }; }, create: function(conf) { var el = $('<button />'); conf.properties.text.assign(function(text) { el.text(text); }); conf.streams.clicked.plug(el.asEventStream('click')); return { el: el }; }, }; var streams1 = mkButton.streams(); var streams2 = mkButton.streams(); var logic = function(s) { return s.clicked.map(constant(1)).scan(0, function(a, b) { return a + b; }); }; var button1 = mkButton.create({ properties: { text: logic(streams2) }, streams: streams1, }); var button2 = mkButton.create({ properties: { text: logic(streams1) }, streams: streams2, }); $('body').append(button1.el).append(' ').append(button2.el); }); button から出る EventStream を Bus として 取得できるようにしておく 先に EventStream だけ 取得しておいて、 一緒に EventStream (Bus) を渡す EventStream から Property を作成
36.
例: Cross Counting
Button $(function() { var constant = function(x) { return function() { return x; }; }; var mkButton = { streams: function() { return { clicked: new Bacon.Bus() }; }, create: function(conf) { var el = $('<button />'); conf.properties.text.assign(function(text) { el.text(text); }); conf.streams.clicked.plug(el.asEventStream('click')); return { el: el }; }, }; var streams1 = mkButton.streams(); var streams2 = mkButton.streams(); var logic = function(s) { return s.clicked.map(constant(1)).scan(0, function(a, b) { return a + b; }); }; var button1 = mkButton.create({ properties: { text: logic(streams2) }, streams: streams1, }); var button2 = mkButton.create({ properties: { text: logic(streams1) }, streams: streams2, }); $('body').append(button1.el).append(' ').append(button2.el); }); 渡された Bus に、 クリックの EventStream をつなげる
37.
例: Cross Counting
Button $(function() { var constant = function(x) { return function() { return x; }; }; var mkButton = { streams: function() { return { clicked: new Bacon.Bus() }; }, create: function(conf) { var el = $('<button />'); conf.properties.text.assign(function(text) { el.text(text); }); conf.streams.clicked.plug(el.asEventStream('click')); return { el: el }; }, }; var streams1 = mkButton.streams(); var streams2 = mkButton.streams(); var logic = function(s) { return s.clicked.map(constant(1)).scan(0, function(a, b) { return a + b; }); }; var button1 = mkButton.create({ properties: { text: logic(streams2) }, streams: streams1, }); var button2 = mkButton.create({ properties: { text: logic(streams1) }, streams: streams2, }); $('body').append(button1.el).append(' ').append(button2.el); }); 副作用 (値変化時の処理登録、 テキストの中身を変更) 副作用 (DOM 要素登録) 副作用 (Bus につなぐ)
38.
リクエスト処理
39.
Bacon.fromPromise • jQuery の
ajax 系メソッドが返 す Promise オブジェクトから、 EventStream を作る。
40.
Bacon.fromPromise • jQuery の
ajax 系メソッドが返 す Promise オブジェクトから、 EventStream を作る。 assign は、イベント登録 を解除する関数を返す 流れてきたレスポンス
41.
• レスポンスがエラーの場合、そのままでは assign
等に流れていかない。 エラーレスポンスの処理
42.
エラーレスポンスの処理 • レスポンスがエラーの場合、そのままでは assign
等に流れていかない。 • mapError メソッドを使って、エラー系の流れを変換関数を通して本流へ流 す。 流れてきたエラーレスポンス エラー系の流れをそのまま本流へ
43.
EventStream#flatMap/flatMapLatest • EventStream が流れてくる
EventStream を、中の EventStream に流れる値が 流れてくる EventStream にする 引用: https://github.com/raimohanska/bacon.js/wiki/Diagrams 引用: https://github.com/raimohanska/bacon.js/wiki/Diagrams flatMap flatMapLatest
44.
EventStream#flatMap/flatMapLatest • EventStream が流れてくる
EventStream を、中の EventStream に流れる値が 流れてくる EventStream にする 引用: https://github.com/raimohanska/bacon.js/wiki/Diagrams 引用: https://github.com/raimohanska/bacon.js/wiki/Diagrams flatMap flatMapLatest 全部流す 後の結果の方が速ければ、前の結果は流れない
45.
リクエスト処理の例 右に入力したパスに GET リクエストを飛ばす 返ってきたレスポンスを表示
46.
ヘルパ var constant =
function(x) { return function() { return x; }; }; var id = function(x) { return x; }; var left = function(x) { return function(f, g) { return f(x); }; }; var right = function(x) { return function(f, g) { return g(x); }; }; var mkButton = { streams: function() { return { clicked: new Bacon.Bus() }; }, create: function(conf) { var el = $('<button />'); conf.properties.text.assign(function(text) { el.text(text); }); conf.properties.enable.assign(function(enable) { el.attr('disabled', !enable); }); conf.streams.clicked.plug(el.asEventStream('click')); return { el: el }; }, }; var mkTextarea = function(conf) { var el = $('<textarea />'); conf.val.assign(function(text) { el.val(text); }); return { el: el }; };
47.
ヘルパ var constant =
function(x) { return function() { return x; }; }; var id = function(x) { return x; }; var left = function(x) { return function(f, g) { return f(x); }; }; var right = function(x) { return function(f, g) { return g(x); }; }; var mkButton = { streams: function() { return { clicked: new Bacon.Bus() }; }, create: function(conf) { var el = $('<button />'); conf.properties.text.assign(function(text) { el.text(text); }); conf.properties.enable.assign(function(enable) { el.attr('disabled', !enable); }); conf.streams.clicked.plug(el.asEventStream('click')); return { el: el }; }, }; var mkTextarea = function(conf) { var el = $('<textarea />'); conf.val.assign(function(text) { el.val(text); }); return { el: el }; }; Either
48.
ヘルパ var constant =
function(x) { return function() { return x; }; }; var id = function(x) { return x; }; var left = function(x) { return function(f, g) { return f(x); }; }; var right = function(x) { return function(f, g) { return g(x); }; }; var mkButton = { streams: function() { return { clicked: new Bacon.Bus() }; }, create: function(conf) { var el = $('<button />'); conf.properties.text.assign(function(text) { el.text(text); }); conf.properties.enable.assign(function(enable) { el.attr('disabled', !enable); }); conf.streams.clicked.plug(el.asEventStream('click')); return { el: el }; }, }; var mkTextarea = function(conf) { var el = $('<textarea />'); conf.val.assign(function(text) { el.val(text); }); return { el: el }; }; ボタンの 有効/無効 も Property で受け取る
49.
ヘルパ var constant =
function(x) { return function() { return x; }; }; var id = function(x) { return x; }; var left = function(x) { return function(f, g) { return f(x); }; }; var right = function(x) { return function(f, g) { return g(x); }; }; var mkButton = { streams: function() { return { clicked: new Bacon.Bus() }; }, create: function(conf) { var el = $('<button />'); conf.properties.text.assign(function(text) { el.text(text); }); conf.properties.enable.assign(function(enable) { el.attr('disabled', !enable); }); conf.streams.clicked.plug(el.asEventStream('click')); return { el: el }; }, }; var mkTextarea = function(conf) { var el = $('<textarea />'); conf.val.assign(function(text) { el.val(text); }); return { el: el }; }; 出力用テキストエリア 設定は出力値 Property のみ。
50.
実装 var input =
$('<input type="text" />').width(400); var bs = mkButton.streams(); var request = bs.clicked.map(function() { return input.val(); }); var response = request.flatMapLatest(function(url) { return Bacon.fromPromise($.get(url)).map(right) .mapError(function(e) { return left(e.responseText); }); }); var button = mkButton.create({ properties: { text: Bacon.constant('request'), enable: Bacon.once(true) .merge(request.map(constant(false))) .merge(response.map(constant(true))) .toProperty(), }, streams: bs, }); var output = mkTextarea({ val: response.map(function(r) { return r(function(msg) { return 'error - ' + msg; }, id); }).toProperty(), }); $('body') .append($('<p />').append(input).append(' ').append(button.el)) .append($('<p />').append(output.el.width(500).height(200)));
51.
実装 var input =
$('<input type="text" />').width(400); var bs = mkButton.streams(); var request = bs.clicked.map(function() { return input.val(); }); var response = request.flatMapLatest(function(url) { return Bacon.fromPromise($.get(url)).map(right) .mapError(function(e) { return left(e.responseText); }); }); var button = mkButton.create({ properties: { text: Bacon.constant('request'), enable: Bacon.once(true) .merge(request.map(constant(false))) .merge(response.map(constant(true))) .toProperty(), }, streams: bs, }); var output = mkTextarea({ val: response.map(function(r) { return r(function(msg) { return 'error - ' + msg; }, id); }).toProperty(), }); $('body') .append($('<p />').append(input).append(' ').append(button.el)) .append($('<p />').append(output.el.width(500).height(200))); ボタンがクリックされると 入力値が流れる EventStream
52.
実装 var input =
$('<input type="text" />').width(400); var bs = mkButton.streams(); var request = bs.clicked.map(function() { return input.val(); }); var response = request.flatMapLatest(function(url) { return Bacon.fromPromise($.get(url)).map(right) .mapError(function(e) { return left(e.responseText); }); }); var button = mkButton.create({ properties: { text: Bacon.constant('request'), enable: Bacon.once(true) .merge(request.map(constant(false))) .merge(response.map(constant(true))) .toProperty(), }, streams: bs, }); var output = mkTextarea({ val: response.map(function(r) { return r(function(msg) { return 'error - ' + msg; }, id); }).toProperty(), }); $('body') .append($('<p />').append(input).append(' ').append(button.el)) .append($('<p />').append(output.el.width(500).height(200))); 入力が流れてきたら、 リクエストを飛ばす
53.
実装 var input =
$('<input type="text" />').width(400); var bs = mkButton.streams(); var request = bs.clicked.map(function() { return input.val(); }); var response = request.flatMapLatest(function(url) { return Bacon.fromPromise($.get(url)).map(right) .mapError(function(e) { return left(e.responseText); }); }); var button = mkButton.create({ properties: { text: Bacon.constant('request'), enable: Bacon.once(true) .merge(request.map(constant(false))) .merge(response.map(constant(true))) .toProperty(), }, streams: bs, }); var output = mkTextarea({ val: response.map(function(r) { return r(function(msg) { return 'error - ' + msg; }, id); }).toProperty(), }); $('body') .append($('<p />').append(input).append(' ').append(button.el)) .append($('<p />').append(output.el.width(500).height(200))); 正常レスポンスを Right で包んでおいて、
54.
実装 var input =
$('<input type="text" />').width(400); var bs = mkButton.streams(); var request = bs.clicked.map(function() { return input.val(); }); var response = request.flatMapLatest(function(url) { return Bacon.fromPromise($.get(url)).map(right) .mapError(function(e) { return left(e.responseText); }); }); var button = mkButton.create({ properties: { text: Bacon.constant('request'), enable: Bacon.once(true) .merge(request.map(constant(false))) .merge(response.map(constant(true))) .toProperty(), }, streams: bs, }); var output = mkTextarea({ val: response.map(function(r) { return r(function(msg) { return 'error - ' + msg; }, id); }).toProperty(), }); $('body') .append($('<p />').append(input).append(' ').append(button.el)) .append($('<p />').append(output.el.width(500).height(200))); 正常レスポンスを Right で包んでおいて、 エラーレスポンスは Left で包んで本流へ
55.
実装 var input =
$('<input type="text" />').width(400); var bs = mkButton.streams(); var request = bs.clicked.map(function() { return input.val(); }); var response = request.flatMapLatest(function(url) { return Bacon.fromPromise($.get(url)).map(right) .mapError(function(e) { return left(e.responseText); }); }); var button = mkButton.create({ properties: { text: Bacon.constant('request'), enable: Bacon.once(true) .merge(request.map(constant(false))) .merge(response.map(constant(true))) .toProperty(), }, streams: bs, }); var output = mkTextarea({ val: response.map(function(r) { return r(function(msg) { return 'error - ' + msg; }, id); }).toProperty(), }); $('body') .append($('<p />').append(input).append(' ').append(button.el)) .append($('<p />').append(output.el.width(500).height(200))); レスポンスが返ってくるまでは ボタンを無効にする
56.
実装 var input =
$('<input type="text" />').width(400); var bs = mkButton.streams(); var request = bs.clicked.map(function() { return input.val(); }); var response = request.flatMapLatest(function(url) { return Bacon.fromPromise($.get(url)).map(right) .mapError(function(e) { return left(e.responseText); }); }); var button = mkButton.create({ properties: { text: Bacon.constant('request'), enable: Bacon.once(true) .merge(request.map(constant(false))) .merge(response.map(constant(true))) .toProperty(), }, streams: bs, }); var output = mkTextarea({ val: response.map(function(r) { return r(function(msg) { return 'error - ' + msg; }, id); }).toProperty(), }); $('body') .append($('<p />').append(input).append(' ').append(button.el)) .append($('<p />').append(output.el.width(500).height(200))); 正常レスポンスはそのまま出力 エラーレスポンスは ‘error - ’ に続けて出力
57.
設計 • 実際には、streams から
properties を作る部分や、リクエストを飛ばす部分 は、別モジュールにしておくといい。 ViewLogic Storage Ajax App get streams, create from properties create properties from streams and storages create response-streams
Download