기본 콘텐츠로 건너뛰기

라벨이 reactive인 게시물 표시

RxJS 에서 GameScene 을 구현하고 있다.

결과물은 여기에 http://jsbin.com/wuhega/edit?js,output Reactive Programming 의 장점+효용이 극대화되는 분야는 아무래도 게임이지 않을까 싶어서 짬을 내어 RxJS로 슈팅게임을 만들고 있다. 배경+플레이어+총알:  https://jsbin.com/worewow/edit?js,output 1+적+폭파에니메이션:  https://jsbin.com/modedic/edit?js,output 2+coffee+적 움직임등 :  https://jsbin.com/yobuka/ 대략, 이런 흐름으로 살을 조금씩 붙여가면서 올리고 있는데 어느정도 튜토리얼을 만들려는 생각으로 ECMA6를 가지고 시작을 했지만 {}, (), [] 괄호노동을 통한 손목터널증후근과 코딩하는 시간 만큼 쌍 맞추는 시간이 소모되는 자신을 발견하고 개인의 행복을 위해(...) 다시 coffeescript로 바꿔서 진행하고 있다. 살 것 같다. 아효. 아마도 곧 합쳐질 것 같지만 어느정도 내용물이 만들어졌으니 이것들을 감싸는 껍데기를 어떻게 만들지 코드를 짜면서 고민해보았다. 일단 크게 나누어 보기를 Splash Scene - 한번만 노출. 게임명과 제작자에 대해 알리는 화면 Title Scene - 게임시작을 위해 대기하는 화면 Game Scene - 실제 게임 화면 GameOver Scene - 게임을 더 이상할 수 없는 상황. 이정도로 잡고 1>2>3>4>2>... 의 반복 구조로 설계를 해보기로 했다. 아무런 레퍼런스도 없고 검색해 본 것도 없어서 매우 삽질이 예상되지만 그래도 FRP(Functional Reactive Programming)원칙에 충실하려고 노력했다. 먼저, 화면을 준비한다. 'use strict' ### setup canvas ### c = document.createElement 'canvas' ...

ReactiveX / RxJS - 상태(State)에 대한 두 가지 접근

RxJS, BaconJS, Highland, 등등 정말 Stream 전성시대. FRP( Functional Reactive Programming )가 흥하는 시대를 살고 있는 느낌이다. 기존의 Array에 람다 함수들에 시간 개념이 들어간 정도인데 그렇다면 데이터가 이렇게 흘러가고 있다면 어떻게 상태가 변할때 마다 표현할지 고민하는데 그걸 State Store 라는 걸 사용해서 상태의 변화를 Reduce (Rx에선 scan) 하여 반영한다. 가령 기존의 Control Flow 기반 프로그래밍에선 1. 상태 변수를 생성한다. 2. 이벤트가 발생한다. 3. 이벤트 콜백을 실행하여 상태 변수를 갱신한다. 4. 상태 변수를 UI에 반영한다. 였다면 RxJS같은 Data Flow 기반 프로그래밍에선 1. 이벤트를 발행한다. 2. 이벤트를 상태 변화로 변환(map)한다. 3. 2를 reduce 한 스트림을 구독한다. 4. 3의 스트림이 발생할 때마다 UI에 반영한다. 정도의 차이라고 볼 수 있겠다. 그러니까 오늘의 나는 태어날 때의 나부터 어제의 나까지를 리듀스 한 것이라고 (.....) ... 같은 건 없다. (출처: twitter ) http://jsbin.com/bowumar  에 클릭 카운터를 구현해보았다. let $=(e=>document.querySelector(e)); let approach1=()=>{   let clickStream=new Rx.BehaviorSubject(0);   $("#inc").addEventListener('click',e=>clickStream.next(1));   $("#dec").addEventListener('click',e=>clickStream.next(-1));   clickStream.scan((x,y)=>x+y).subscribe(o=>$("#count...

ReactiveX(Rx), Promise, 그리고 Future

Rx를 하다보니 fiber/future도 새롭게 보인다. 가령 비동기 구간을 setTimeout -> ..... , 1000 으로 하는 구현을 해보자. Rx.Observable.create (observable)->   # callback block   setTimeout ->     observable.onNext "<결과값>"   , 1000 .subscribe (res)->   console.log res 요건 Promise로 풀면 new Promise (resolve, reject)->   # callback block   setTimeout ->     resolve "<결과값>"   , 1000 .then (res)->   console.log res 거의 같은 모양을 하고 있다. 그 fiber/future로 풀면 doSomeAsync = ->   future = new Future()   setTimeout ->     future.return "<결과값>"   ,1000   future.wait() console.log doAsync() 핵심은 동기에서 return 에 들어갈 부분이 대체되고 그걸 외부에서 받는 부분이랑 한 쌍을 구성한다는 점인데 future는 c coroutine library 인 libcoro( https://github.com/ramonza/libcoro )를 사용하고 있다.  사실 coroutine만 해도 c에서 구현만 http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html  이렇게 다양한데. ECMA6 (coffeescript 1.10.0)...

RxJS 연습.

http://jsbin.com/roweju  에 해보고 있음. Rx.Observable 에 fromEvent 를 붙여서 click 눌렀을 때 카운트가 올라가는 건 솔직히 잘 모르겠고 map으로 가공하고 최종결과를 subscribe 하는 패턴은 재미있다. 비동기 실행을 하는 부분은  Rx.Observable.create (observer)-> 로 시작해서 observer.next( 리턴값 ) 형식으로 끝나는 건 promise 랑 되게 비슷한 패턴이다. .flatMap은    .map (url)-> sendRequest url, 'GET', null    .mergeAll() 이 두개를 합친 것이라고 보면 됨. * HTML <!DOCTYPE html> <html> <head> <script src="https://npmcdn.com/@reactivex/rxjs@5.0.0-beta.7/dist/global/Rx.umd.js"></script>   <meta charset="utf-8">   <meta name="viewport" content="width=device-width">   <title>JS Bin</title> </head> <body>   <button id="btn">click</button>   <p><span id="counter">1</span>th click</p>   <button id="btn-get">get posts</button>   <pre id="result">   </pre> </b...

Tracker+DDP+Mithril=Success!

Mithril 을 좀 보고 있다. 무엇보다 가볍고 (12kb) 성능이 어마어마( http://matt-esch.github.io/mercury-perf/ )하고 디자인 사상도 매우 깔끔해서 마음에 들었다. 그래서 혹시 Meteor랑 같이 쓸 방법은 없을까 해서 뒤적거려 보았더니 http://lhorie.github.io/mithril-blog/mithril-and-meteor.html 아주 좋은 글이 있더라. Mithril을 Meteor에서 사용하면서 Reactivity를 구현하기 위해 Deps(현재는 Tracker)객체를 controller에 붙이고 unload 될때 computation을 멈추는 것까지 아주 깔끔하게 구현해 놓았다. 만든이가  https://github.com/meteor/meteor/wiki/Tracker-Manual  의 내용을 잘 숙지하고 있는 것 같다. React에서 getMetadata + Mixins를 사용하는 방법보다 더 납득이 가는 방식이었다. 그렇다면, 꼭 Meteor를 전부쓰지 않더라도 Mithril에서 Tracker package만 사용하고 DDP를 엮는 것만으로도 굉장히 가볍고 강력한 클라이언트쪽 Reactive Programming 구현을 할 수 있겠다 싶었다 DDP서버로만 Meteor를 사용해도 되고 PythonDDP, GoDDP 같은 것들이 있으니까 node.js를 사용하지 않아도 별 상관이 없다. 강력하다! GDG모임에서 React+Meteor Lightning Talk 발표를 하면서 조금 React를 공부해서 그런지 생각이 정리가 잘 되어서 쉽게 검증해볼 수 있었는데. 먼저 필요한 라이브러리들을 모아보았다. 1. Meteor Tracker Package https://github.com/meteor/meteor/tree/devel/packages/tracker 2. Meteor Javascript DDP (/w promise)  https://...

Meteor 경량 Reactive package - ReactiveVar를 사용해보자.

예전 글인 Session으로 Reactive 실시간 타이머에 대한 성원에 힘입어 추가로 하나 더. http://meteorpad.com/pad/LybNGiNShhNvjCBPD/timeAgo-reactiveVar  예제를 보자. 나머지는 다 비슷하고 Session 이 아니라 reactive-var package를 사용했다. meteor add reactive-var 로 추가할 수 있다. Session과 다른 건 비슷하고 key,val 형식이 아니고 Hot code push를 통해 값을 보존할 수 없으며 Global Scope 가 아니다. 사실 이것 때문에 쓴다고 봐도 된다. Session은 사실 클라이언트의 부담을 주기 때문에 무분별하게 사용하는 것은 좋지 않다. var count = new ReactiveVar(Random.id()); 와 같이 직접 선언해주고 count.set(value),  count.get() 으로 사용하면 된다. 눈치채신 분들도 있을지 모르겠는데  http://meteor.github.io/blaze/  의 Blaze.Var 하고 아주 비슷하다. http://docs.meteor.com/#/full/reactivevar 내용을 참조하면 된다. 구현도 아주 간단해서 https://github.com/meteor/meteor/blob/master/packages/reactive-var/reactive-var.js#L37 메뉴얼 대신 봐도 될 정도. 그러고보니 예전엔 Deps를 꽤 중요하게 강조했던 때도 있었는데 Tracker로 바뀌면서 이런 패키지를 만들었나보다. 재미있는 것은 Optional로 ReactiveVar를 생성 시 두번째 인자인 equalsFunc 에 function을 정의할 수 있는데 이것이 true를 반환하면 set 할때 Reactive 가 작동하지 않는다. 가볍고 고성능인 패키지이니 Session이 넘쳐난다고 있다면 성능을 높이기 위해 한번 써보자....

Meteor - Session을 이용한 살아있는 Reactive 게시 시간(moment 사용)

facebook 같은 SNS를 보면 게시글과 댓글의 시간이 실시간으로 갱신되는데 Meteor를 사용하면 불필요한 DOM을 갱신하지 않고 필요한 부분만 적은 코드로 구현할 수 있습니다. 현재 시간 기준으로 얼마나 시간이 흘렀는지 (ex. 5 minute ago) 보여주려면 moment(기준시간).fromNow() 를 사용하면 됩니다. helper를 만들어보면 <span>{{timeAgo createdAt}}</span> .... Template.main.helpers({   ...   "timeAgo": function(time) {     return moment(time).fromNow();   } }); 이와 같이 구현할 수 있죠. 여기에서 우리는 Template의 helper가 Reactive Computation 대상이며Session이 Reactive Data Source라는 점을 사용합니다. ( http://docs.meteor.com/#/full/reactivity ) Reactive Computation 대상인 helper 안에서 Session의 값이 갱신되면 helper를 다시 호출하지 않아도 다시 갱신이 되는 것입니다. 1초마다 특정 Session의 값을 갱신하도록 해봅시다. onCreated에서 interval을 생성하고 onDestroy에서 제거하도록 하여 불필요한 부담을 줄여줍니다. Template.main.onCreated(function() {   Session.set("localtime",1);   this.interval = Meteor. setInterval (function() {     Session.set("localtime", Random.id() );   }, 1000); }); .... Template.main.onDestroyed(func...