July 14, 2020
이전보다 개인적으로 공부 할 시간이 남게 되어서 이전에 스터디 참여했던 Code spitz 85 [Non blocking Javascript] 를 복습하려고 한다. 당시에 회사 다니면서 어렵게 참여해서 들었던 시간을 헛되게 넘기고 싶지 않아서 이번에 복습을 제대로 해봐야겠다. 2강부터 다시 복습하게 된 이유는…가장 열심히 들었고 이 수업 중 가장 많이 이해했던 강의다. 이번엔 꼭 제대로 공부해봐야겠다.
하나의 task 가 메모리를 할당하고 있으면, 다른 task 는 좌절, 탈취, 대기를 할 수 있다.
( ex. java는 Object 에 wait가 있어서 대기를 할 수 있음 )
engine work (rendering…)
check queue ← calback queue ( network, timer, message, dom event : parallelism 으로 되어있음)
run JS - 자바스크립트를 빠르게 실행이 될 수 있게 작성 해야 함 (engine work, check queue는 우리가 할 수 없음)
const Item = class {
time; // 시간
block; // 실행 될 함수
constructor (block, time) {
this.block = block;
this.time = time + performance.now() // performance.now() 브라우저가 시작 된 이후의 몇초가 지났는지
}
}
const queue = new Set; // 배열은 사실상 값만 저장하기때문에, 중복되지않은 객체를 저장하고 싶다면 Set을 사용ㅇ
// check queue function
const f = time => {
queue.forEach(item => { // ES6부터는 forEach 는 복사본을 돌리기 때문에 delete를 해도 무방함
if (item.time > time) return
queue.delete(item)
item.block()
})
requestAnimationFrame(f)
}
requestAnimationFrame(f)
//
const timeout = (block, time) => queue.add(new Item(block, time))
timeout(_=> console.log("hello"), 1000)
알아야 하는 것
const working =_=> {} // ES6 화살표함수는 인자가 없으면 () 생략하고 _를 할 수 있음
for (let i = 0; i < 100000; i++) working()
const nbFor = (max, load, block) => {
let i = 0 // i count 를 max-1까지 돌리기
const f = time => {
let curr = load
while(curr-- && i < max) { // 최대 100번만 돌 수 있고, max보다 i가 더 크면 아예 못돌게 작성
block()
i++
}
console.log(i)
if (i < max - 1) timeout(f, 0) // 100번만 돌고, engine 에게 다시 돌려줘서 engine work 를 할 수 있다. (제어권 돌려줌)
// timeoout function 을 사용해서 requestAnimationFrame 을 숨ㄱㅁ
}
timeout(f, 0)
}
nbFor(100, 10, working)
위 설명
i 는 함수를 실행할 때, 0 으로 초기화 되며 함수를 실행하는 동안 상태가 보존된다.
→ closer 패턴
// 메모리를 할당하고 있지 않아도 무한으로 만들 수 있다.
const infinity = (function *(){ // *를 붙이면 suspend 라는 구간을 만든다.
let i = 0
while (true) yield i++ // yield 를 호출하면 suspend. yield 가 호출되면서 멈춤.
})() // iterator 바로 실행
console.log(infinity.next()) // iterator 의 객체로 next 호출 가능
// next 를 호출할 때 마다 yield 에서 다시 호출되면서 resume
const gene = function*(max, load, block) {
let i = 0, curr = load
while (i < max) { // 다른 서브 루틴을 만들지 않고, 하나의 루프로 작업
if (curr--) {
block()
i++
} else {
curr = load
console.log(i)
yield// suspend 걸어서 외부에 제어를 위임한다.(반제어)**
}
}
}
→ 제어 구조를 가지고 있지만, yield (suspend 걸기) 하면 제어의 일부를 바깥으로 위임하여 하고싶은 일을 바깥에서 할 수 있다. (제어 역전의 일부)
제어 문은 복사해서 써 올 수 밖에 없음. 재활용을 할 수가 없다.
명령문 ( if, while, …) 으로 만들면 재활용을 하지 못하고 실행되면 사라짐. 그러므로 값으로 만들어야 함. (값은 메모리에 저장되어 있기 때문에)
const nbFor = (max, load, block) => {
const iterator = gene(max, load, block) // iterator : **value, done** 이 있는 object 를 return 함
const f =_=> iterator.next().done || timeout(f)
timeout(f, 0) //timeout 분리 성공
}
nbFor(100, 10, working)
const gene2 = function*(max, load, block) {
let i = 0, curr = load
while (i < max) {
yield new Promise(res => { // Promise return
let curr = load
while (curr-- && i < max) {
block()
i++
}
coonsole.log(i)
timeout(res, 0) // then 에 대한 통제권을 바깥에서 가지게 돔
})
}
}
// 제어권은 다 Promise 에 가있고, 아래 함수는 실행만 해주는 함수 (단순 실행)
// Generator Co pattern
const nbFor = (max, load, block) => {
const iterator = gene2(max, load, block)
const next = ({value, done}) => done || value.then(v => next(iterator.next())) // yield 해소 부분
next(iterator.next())
}