✊ 필오의 개발일지
Back to Posts
2019년 11월 11일

코드스피츠85 2회-(2) 동시성 모델을 직접 구현하며 이해하기.

코드스피츠85 2회-(2) 동시성 모델을 직접 구현하며 이해하기.

코드스피츠 85에서는 none blocking에 대한 이야기와 자바스크립트를 짜는 근본적인 방법에 대한 고찰을 이야기해본다.


🌕🌑🌑

TL;DR

setTimer에서부터 promise까지 동시성 모델을 기반으로 구현하며, 루프 제어권의 통제에 대하여 알아본다.


1. setTimer를 구현해보기

entity

  1. Item
  1. queue
const Item = class { time: number; // 몇초 후에 실행할지 block: Function; // 몇초 후에 실행할 함수 constructor(block, time) { this.block = block; this.time = time + performance.now(); } }; const queue = new Set();

cf__1. performace, Set, value

  • performance.now()
    • 브라우저가 실행되 이후에 지난 시간
    • date.now()보다 좋은 점은 나노초까지 볼 수 있다.
  • Set
    • 배열에 담을 수 있는건 값만 담을 수 있다.
    • 같은 객체가 중복으로 들어가지 않는다.
    • 객체를 담는 리스트
  • value
    • 불변
    • 자체의 값으로 판단한다.
    • 값으로 식별된다.

Core Action

  1. callback 큐를 지속적으로 체크한다.
@params time 현재시간 const checkQueue = (time: number) => { queue.forEach((item: {time: number, block: Function}) => { if(item.time > time) return; // 현재시간이 호출시간보다 작다면 실행하지 않음. else { // 현재시간이 호출시간보다 작다면 실행. queue.delete(item); // 실행할 예정이기때문에 삭제 item.block(); // 실행 } }); requestAnimationFrame(checkQueue); } requestAnimationFrame(checkQueue);

cf__2 requestAnimationFrame


트리거

const timeout = (block: Funtion, time: number) => queue.add(new Item(block, time));

확인해보자.

timeout(_ => console.log('hello'), 1000);

정리

방금 구현한 setTimer를 동시성 모델로 구현해보면?

좀더 큰 그림에서 보면?



2. Non Blocking For 구현해보기

const working = _ => {}; for(let i=0; i < 100000; i++) working(); @params max 최대 루프수 @params load 한번에 로드할 카운트 @params block 실행할 함수 const nbFor = (max:number, load: number, block: Function) => { let i = 0; const f = (time:number) => { let curr = load; // 한번에 로드할 카운트를 상태로 받기 위해 변수에 할당 while(curr-- && i < max) { // 1. 1회돌때마다 현재 상태를 하나씩 뺀다. block(); // 2. 실행 i++; } console.log(i); if(i < max-1) requestAnimationFrame(f) } requestAnimationFrame(f); // --- (1) }
  1. requestAnimationFrame으로 내부함수 f가 실행
  2. load기준으로 반복 카운트가 chunk된다.
  3. while문이 한 셋트가(load 카운트가 종료) 끝나면, requestAnimationFrame으로 f함수를 다시 실행시킨다.
  1. 다시
  2. max까지 루프가 끝나면 더이상 f를 실행하지 않음.


3. Generator 구현해보기

const infinity: Iterator = (function* () { let i = 0; while (true) yield i++; })(); console.log(infinity.next());
// lib.es2015.iterable.d.ts interface IteratorResult<T> { done: boolean; value: T; } interface Iterator<T> { next(value?: any): IteratorResult<T>; return?(value?: any): IteratorResult<T>; throw?(e?: any): IteratorResult<T>; }

function*

const gene = function* (max: number, load: number, block: Function) { let i = 0, curr = load; while (i < max) { if (curr--) { block(); i++; } else { curr = load; // curr을 초기화하고 console.log(i); yield; // 제어권을 밖에 둔다. } } };
const nbFor = (max, load, block) => { const iterator: Iterator = gene(max, load, block); const f = _ => iterator.next().done || timeout(f); timeout(f); // timeout을 쓰는 위치를 밖으로 옮겼다. };

제어 시스템의 반제어권을 외부에 줌으로써 내부에서 제어와 관련된 로직을 분리시킬수 있게 된다는게 제너레이터의 장점



4. Promise 구현해보기

  1. 트리거를 걸었음
  2. 서버가 3초만에 데이터를 줬음
  3. 3초 안에는 제어할 권한이 없음
  4. 3초 이후에는 제어할 권한이 있음
const gene2 = function* (max, load, block) { let i = 0; while (i < max) { yield new Promise(res => { let curr = load; while (curr-- && i < max) { block(); i++; } console.log(i); timeout(res, 0); }); } };
const nbFor = (max, load, block) => { const iterator: Iterator<Promise> = gene2(max, load, block); const next = ({ value, done }) => dome || value.then(v => next(iterator.next())); next(iterator.next()); };

참고자료

Previous클라이언트 식별
Next코드스피츠85 2회-(1) 자바스크립트의 동시성

Related

© 2026 Felix