왜 이름이 Driver 인가
OS에서 외부하드웨어와 연결하는 소프트웨어를 Driver라고 하는데 외부로부터 영향(effect)를 주고 영향을 받는다는 점에서 아이디어를 얻음.
DOM Driver
Sink가 없는 형태의 Driver
Driver 만드는 법
다시 Sock(가짜 실시간 리얼타임 채널 API) 구현
effect가 어떤 것인지 가려내보자
write effect는 sock.send(msg) 일테고
read effect는 sock.onReceive
adapt를 가져와서
OS에서 외부하드웨어와 연결하는 소프트웨어를 Driver라고 하는데 외부로부터 영향(effect)를 주고 영향을 받는다는 점에서 아이디어를 얻음.
DOM Driver
Sink가 없는 형태의 Driver
function WSDriver(/* no sinks */) {websocket의 예
return xs.create({
start: listener => {
this.connection = new WebSocket('ws://localhost:4000');
connection.onerror = (err) => {
listener.error(err)
}
connection.onmessage = (msg) => {
listener.next(msg)
}
},
stop: () => {
this.connection.close();
},
});
}
Driver 만드는 법
function myDriver(sink$, name /* optional */)부터 시작.
다시 Sock(가짜 실시간 리얼타임 채널 API) 구현
// Establish a connection to the peer이렇게 일단 가정.
let sock = new Sock('unique-identifier-of-the-peer');
// Subscribe to messages received from the peer
sock.onReceive(function (msg) {
console.log('Received message: ' + msg);
});
// Send a single message to the peer
sock.send('Hello world');
effect가 어떤 것인지 가려내보자
write effect는 sock.send(msg) 일테고
read effect는 sock.onReceive
import {adapt} from '@cycle/run/lib/adapt';구현은 이렇게.
function sockDriver(outgoing$) {
outgoing$.addListener({
next: outgoing => {
sock.send(outgoing);
},
error: () => {},
complete: () => {},
});
const incoming$ = xs.create({
start: listener => {
sock.onReceive(function (msg) {
listener.next(msg);
});
},
stop: () => {},
});
return adapt(incoming$);
}
adapt를 가져와서
- outgoing 스트림을 인자로 받는다.
- outgoing 스트림에 대해 Listener(subscriber)를 추가한다.
- subscriber는 outgoing 스트림에서 받아 sock.send 를 한다.
- incoming 스트림은 start에 sock이 데이터를 받을 때 해당 인자(listener)의 next로 받은 메시지를 보낸다.
- incoming 스트림을 adapt의 인자로 반환하는 것으로 마무리
여기까지가 sockDriver 라면 Sock을 생성하는 것을 포함한 makeSockDriver를 만들어본다.
import {adapt} from '@cycle/run/lib/adapt';
function makeSockDriver(peerId) {
let sock = new Sock(peerId);
function sockDriver(outgoing$) {
outgoing$.addListener({
next: outgoing => {
sock.send(outgoing));
},
error: () => {},
complete: () => {},
});
const incoming$ = xs.create({
start: listener => {
sock.onReceive(function (msg) {
listener.next(msg);
});
},
stop: () => {},
});
return adapt(incoming$);
}
return sockDriver;
}
makeSockDriver는 peerId라는 인자를 받아 Sock을 생성한다.
실제 사용.
https://github.com/Widdershin/cycle-animation-driver/blob/master/src/driver.js
requestAnimationFrame 을 사용한 Driver 를 보면서 응용의 폭을 생각해보자.
https://www.npmjs.com/package/cycle-canvas
Canvas에도 마찬가지로 적용할 수 있다.
https://github.com/cyclejs-community/cycle-canvas/blob/master/examples/flappy-bird/index.js
에서 KeysDriver도 흥미롭다.
Driver에 대해 이해하면 Cycle.js 가 더욱 가깝게 느껴진다.
https://github.com/cyclejs-community/cycle-canvas/blob/master/examples/flappy-bird/app.js
flappy bird 예제인데 state에서부터 반복적으로 발생하는 스트림, 화면 갱신 주기. 이 모든 걸 scan하는 것 등등 참으로 알차고 값진 예제다. 이해하기도 쉽고.
실제 사용.
function main(sources) {익숙한 방식이다.
const incoming$ = sources.sock;
// Create outgoing$ (stream of string messages)
// ...
return {
sock: outgoing$
};
}
run(main, {
sock: makeSockDriver('B23A79D5-some-unique-id-F2930')
});
https://github.com/Widdershin/cycle-animation-driver/blob/master/src/driver.js
requestAnimationFrame 을 사용한 Driver 를 보면서 응용의 폭을 생각해보자.
https://www.npmjs.com/package/cycle-canvas
Canvas에도 마찬가지로 적용할 수 있다.
https://github.com/cyclejs-community/cycle-canvas/blob/master/examples/flappy-bird/index.js
에서 KeysDriver도 흥미롭다.
function makeKeysDriver () {이렇게 정의하고
const keydown$ = Observable.fromEvent(document, 'keydown');
function isKey (key) {
if (typeof key !== 'number') {
key = keycode(key);
}
return (event) => {
return event.keyCode === key;
};
}
return function keysDriver () {
return {
pressed: (key) => keydown$.filter(isKey(key))
};
};
}
function App ({Canvas, Keys, Time}) {이렇게 사용한다. space 키에 대한 이벤트에 대해서만 filter한 스트림이 space$가 된다.
...
const space$ = Keys.pressed('space');
...
}
Driver에 대해 이해하면 Cycle.js 가 더욱 가깝게 느껴진다.
https://github.com/cyclejs-community/cycle-canvas/blob/master/examples/flappy-bird/app.js
flappy bird 예제인데 state에서부터 반복적으로 발생하는 스트림, 화면 갱신 주기. 이 모든 걸 scan하는 것 등등 참으로 알차고 값진 예제다. 이해하기도 쉽고.
댓글
댓글 쓰기