1. masakielastic

    No comment

    masakielastic
Changes in body
Source | HTML | Preview
@@ -1,420 +1,420 @@
Cycle.js の勉強を始めて、RxJS の習熟度不足を痛感したので、基本練習に取り組むことにしました。
セットアップ
----------
### RxJS
```bash
npm install rx
```
```javascript
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.min.js"></script>
```
### RxJS-DOM
```bash
npm install rx-dom
```
```js
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs-dom/7.0.3/rx.dom.min.js"></script>
```
### RxJS-jQuery
```bash
npm install rx-jquery
```
```js
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs-jquery/1.1.6/rx.jquery.min.js"></script>
```
### Fetch API
Can I use のサイトで Fetch API に対応するブラウザーの[一覧](http://caniuse.com/#feat=fetch) を調べることができます。古いブラウザーのために、Github が[polyfill](https://github.com/github/fetch) を公開しています。
定義されるメソッドの一覧
--------------------
RxJS は [こちら](https://github.com/Reactive-Extensions/RxJS/tree/master/doc)、RxJS-DOM は[こちら](https://github.com/Reactive-Extensions/RxJS-DOM/tree/master/doc)、RxJS-jQuery は[こちら](https://github.com/Reactive-Extensions/rxjs-jquery)を参照。
プロミス
-------
```js
var promise = new Promise(function (resolve, reject) {
resolve(10);
});
var source = Rx.Observable.fromPromise(promise);
var subscription = source.subscribe(
function (x) { console.log('onNext: %s', x); },
function (e) { console.log('onError: %s', e); },
function () { console.log('onCompleted');
});
var promise2 = new Promise(function (resolve, reject) {
reject(new Error('reason'));
});
var source2 = Rx.Observable.fromPromise(promise2);
var subscription2 = source2.subscribe(
function (x) { console.log('onNext: %s', x); },
function (e) { console.log('onError: %s', e); },
function () { console.log('onCompleted'); }
);
```
ジェネレーター
------------
```js
function* range() {
var index = 0;
while(true) {
yield index++;
}
}
Rx.Observable.from(range())
.take(10)
.subscribe(function (x) {
console.log('値: %s', x);
});
```
-FizzBuzz
---------
+
+
+Ajax
+-----
+
+`httpbin.org` で練習します。
+
+### GET
+
+ES6 Promise に対応している Fetch API を使ってみましょう。Promise から Observable を生成するには `fromPromise` を使います。
+
+```js
+var promise = fetch('http://httpbin.org/get')
+ .then(function(response) {
+ return response.json();
+ }).then(function(json) {
+ return json.origin;
+ }).catch(function(ex) {
+ return ex;
+ });
+
+Rx.Observable.fromPromise(promise)
+ .subscribe(
+ function (value) {
+ console.log(value);
+ },
+ function (err) {
+ console.log('エラー: %s', err);
+ },
+ function () {
+ console.log('完了');
+ });
+```
+
+`Rx.Observable.spawn` を使ってジェネレーターによる非同期処理をやってみよう。
+
+```js
+var Rx = require('rx');
+var request = require('request');
+
+var get = Rx.Observable.fromNodeCallback(request);
+
+Rx.Observable.spawn(function* () {
+ var data;
+
+ try {
+ data = yield get('http://httpbin.org/get').timeout(5000 /*ms*/);
+ } catch (e) {
+ console.log('Error %s', e);
+ }
+
+ console.log(JSON.parse(data[0].body).origin);
+}).subscribe();
+```
+
+### POST
+
+まずは `FormData` を使ってみましょう。`Content-Type` の値は `multipart/form-data` になります。
+
+```js
+var data = new FormData();
+data.append('input', 'bar');
+
+var promise = fetch('http://httpbin.org/post', {
+ method: 'post',
+ body: data
+}).then(function(response) {
+ return response.json()
+ })
+ .then(function(json) {
+ return json.form;
+ })
+ .catch(function(ex) {
+ return ex;
+});
+
+Rx.Observable.fromPromise(promise)
+ .subscribe(
+ function (value) {
+ console.log(value);
+ },
+ function (err) {
+ console.log('エラー: %s', err);
+ },
+ function () {
+ console.log('完了');
+ });
+```
+練習問題
+-------
+
+### FizzBuzz
FizzBuzz から練習をはじめよう。1 から 100 までの整数で構成されるシーケンスを生成するには `Rx.Observable.range` を使う。
```js
var Rx = require('rx');
var source = Rx.Observable.range(1, 100);
source.subscribe(function(value) {
if (value % 15 === 0) {
console.log('fizzbuzz');
} else if (value % 3 === 0) {
console.log('fizz');
} else if (value % 5 === 0) {
console.log('buzz');
} else {
console.log(value);
}
});
```
map を使って FizzBuzz の判定を複数の関数に分割してみよう。
```js
var Rx = require('rx');
var source = Rx.Observable.range(1, 100);
source
.map(function(value) {
return value % 15 === 0 ? 'fizzbuzz' : value;
})
.map(function(value) {
return value % 3 === 0 ? 'fizz' : value;
})
.map(function(value) {
return value % 5 === 0 ? 'buzz' : value;
})
.subscribe(function(value) {
console.log(value);
});
```
複雑なシーケンスを生成できるように `Rx.Observable.generate` が用意されている。
```js
var Rx = require('rx');
var source = Rx.Observable.generate(
1,
function (value) { return value < 101; },
function (value) { return value + 1; },
function (value) {
if (value % 15 === 0) {
return 'FizzBuzz';
} else if (value % 3 === 0) {
return 'Fizz';
} else if (value % 5 === 0) {
return 'Buzz';
} else {
return value;
}
}
);
source.subscribe(function (x) {
console.log(x);
});
```
今度は配列を繰り返す方式に取り組んでみよう。ES6 のジェネレーターで無限のシーケンスを生成し、`take` で最初の100をとる。
```js
var Rx = require('rx');
function *list()
{
var list = [
'', '', 'Fizz', '', 'Buzz',
'Fizz', '', '', 'Fizz', 'Buzz',
'', 'Fizz', '', '', 'FizzBuzz'
];
while (true) {
for (var e of list) {
yield e;
}
}
}
Rx.Observable.from(list())
.take(100)
.map(function(value, index) {
return value === '' ? index + 1: value;
})
.subscribe(function(value) {
console.log(value);
});
```
今度は Fizz と Buzz の生成を分割してみよう。それぞれ別のシーケンスを生成した後で `Rx.Observable.zip` を使って統合する。
```js
var Rx = require('rx');
function *fizz()
{
var list = ['', '', 'Fizz'];
while (true) {
for (var e of list) {
yield e;
}
}
}
function *buzz()
{
var list = ['', '', '', '', 'Bizz'];
while (true) {
for (var e of list) {
yield e;
}
}
}
var source = Rx.Observable.zip(
Rx.Observable.from(fizz()).take(100),
Rx.Observable.from(buzz()).take(100),
function (a, b) {
return a + b;
}
);
source
.map(function(value, index) { return value === '' ? index : value; })
.subscribe(function (x) {
console.log('%s', x);
});
```
-現在時刻を表示する
----------------
-
+### 現在時刻を表示する
1秒単位で現在時刻を表示してみましょう。
```html
<div id="result"></div>
```
```js
var result = document.getElementById('result');
var source = Rx.Observable
.interval(1000)
.timeInterval();
source.subscribe(
function (x) {
result.innerHTML = (new Date()).toLocaleString();
},
function (err) {
console.log('エラー: ' + err);
},
function () {
console.log('完了');
});
```
-ユーザーの入力を表示する
---------------------
-
+### ユーザーの入力を表示する
テキストボックスの入力をそのまま表示させてみましょう。Cycle.js の[トップページ](http://cycle.js.org/)にもコードサンプルが掲載されています。
```html
<input id="textInput" type="text">
<div id="result"></div>
```
```js
var textInput = document.querySelector('#textInput');
var result = document.querySelector('#result');
Rx.Observable.fromEvent(textInput, 'input')
.pluck('target', 'value')
.startWith('')
.subscribe(function(value) {
result.innerHTML = value;
});
```
pluck の代わりに `map` を使うこともできます。
```js
.map(function(ev) { return ev.target.value; })
```
-クリックカウンター
----------------
-
+### クリックカウンター
ボタンをクリックするとカウンターの値が1つ増えるものとします。
```html
<button id="plus">増やす</button>
<div id="result">0</div>
```
```js
var plus = document.getElementById('plus');
var result = document.getElementById('result');
var source = Rx.Observable.fromEvent(plus, 'click')
.map(function() { return +1; })
.startWith(0)
.scan(function(acc, value) { return acc + value; })
.subscribe(function(value) { result.innerHTML = value; });
```
次にクリックするとカウンターの値が1減るボタンおよびカウンターの値が0になるリセットボタンを追加してみましょう。
```html
<button id="plus">増やす</button>
<button id="minus">減らす</button>
<button id="reset">リセット</button>
<div id="counter"></div>
```
```js
var counter = document.getElementById('counter');
var plus = Rx.Observable
.fromEvent(document.getElementById('plus'), 'click').map(function() { return +1; });
var minus = Rx.Observable
.fromEvent(document.getElementById('minus'), 'click').map(function() { return -1; });
var reset = Rx.Observable
.fromEvent(document.getElementById('reset'), 'click').map(function() { return 0; });
Rx.Observable.merge(plus, minus, reset)
.startWith(0)
.scan(function(acc, value) { return value === 0 ? 0 : acc + value; })
.subscribe(function(value) { counter.innerHTML = value; });
```
-
-Ajax
-
-`httpbin.org` で練習します。
-
-### GET
-
-ES6 Promise に対応している Fetch API を使ってみましょう。Promise から Observable を生成するには `fromPromise` を使います。
-
-```js
-var promise = fetch('http://httpbin.org/get')
- .then(function(response) {
- return response.json();
- }).then(function(json) {
- return json.origin;
- }).catch(function(ex) {
- return ex;
- });
-
-Rx.Observable.fromPromise(promise)
- .subscribe(
- function (value) {
- console.log(value);
- },
- function (err) {
- console.log('エラー: %s', err);
- },
- function () {
- console.log('完了');
- });
-```
-
-`Rx.Observable.spawn` を使ってジェネレーターによる非同期処理をやってみよう。
-
-```js
-var Rx = require('rx');
-var request = require('request');
-
-var get = Rx.Observable.fromNodeCallback(request);
-
-Rx.Observable.spawn(function* () {
- var data;
-
- try {
- data = yield get('http://httpbin.org/get').timeout(5000 /*ms*/);
- } catch (e) {
- console.log('Error %s', e);
- }
-
- console.log(JSON.parse(data[0].body).origin);
-}).subscribe();
-```
-
-### POST
-
-まずは `FormData` を使ってみましょう。`Content-Type` の値は `multipart/form-data` になります。
-
-```js
-var data = new FormData();
-data.append('input', 'bar');
-
-var promise = fetch('http://httpbin.org/post', {
- method: 'post',
- body: data
-}).then(function(response) {
- return response.json()
- })
- .then(function(json) {
- return json.form;
- })
- .catch(function(ex) {
- return ex;
-});
-
-Rx.Observable.fromPromise(promise)
- .subscribe(
- function (value) {
- console.log(value);
- },
- function (err) {
- console.log('エラー: %s', err);
- },
- function () {
- console.log('完了');
- });
-```