동기, 비동기, 블럭, 넌블럭
일반적인 함수는 블로킹 함수이며 동기화 함수이다.
동기화 함수와 비동기화 함수는 다른 뜻이다.
동기화 함수는 쉽게 이해할 수 있다. 동기화 함수는 입력하면, 리턴값이 반환되는 것을 의미한다.
비동기화 함수는 리턴값이 반환되지 않는다. 그럼 어떻게 리턴 하는가?
👉🏽 콜백으로 리턴한다. 콜백으로 리턴하는 함수는 다 비동기화 함수이다.
동기형 프로그램은 코드가 순차적으로 실행 되는것을 말한다. 비동기형 프로그램은 코드가 순차적으로 실행되지 않고, 중간에 점프를 해다니는 것을 말한다.
그에 비해 블로킹, 넌블로킹은 전혀 다른 이야기이다.
블로킹이라는 것은, 우리가 폰노이만 머신을 쓰기 때문에 계속해서 명령을 로딩해서 실행하는데, 블로킹이란건 모든 CPU가 정지하고 어떤 명령을 계속 실행하고 있는 상태를 이야기 한다.
예를들면, console.log()를 백번 실행했을때, console.log()한줄을 실행할때도 어차피 시간을 잡아먹긴 잡아먹을것 아닌가? 그러면 한줄한줄도 결국 블로킹 코드이지 않은가? (한줄만 실행해도 cpu타임상으로 한 클럭 먹었기 때문에) 따라서, 블로킹 넌블로킹이냐는 것은 상대적이다.
상대적이라는건, ‘우리가 느끼기에 이정도면 블로킹으로 안볼래’ 이러면 넌블로킹인 것이고, ‘아, 이정도면 충분히 시간을 많이 끈것 같아’ 이러면 블로킹이다.
for loop 100번 도는 것은 우리 느낌에 넌블로킹이다. 똑같은 코드가 for로 20000번 돌면.. 애매해… 200000000번 돌면 블로킹이라 생각한다. 상대적이다.
업계 표준상 넌블로킹의 기준은 얼마 이내에 수행되어야 할까?
16.6밀리세컨드 이다. 초당 60프레임 이내에 소화되면 non-blocking으로 보고 있다. 그것보다 오래걸리면 blocking으로 본다. 그런데 기준이 총 수행 시간이기에 모든함수와 모든 로직을 실행 했을때 16.6밀리세컨드 안에 들어와야한다. 때문에 함수 하나로 보면 보통 1미리 세컨드 이하가 되어야지만 non-block으로 보고 있다.(조합으로 한 프레임을 먹기 때문에.)
Promise는 비동기 함수를 사용하는 callback 스타일을 바꾸어주는 것이라고 알고 있을 것이다. 그런데, 기존의 callback의 문제가 뭘까? callback 지옥인가? promise도 똑같이 지옥이 있다. 뭐가 문제일까? callback의 가장 큰 단점이 무엇일까?
callback함수를 시작한건 우리가 한다. (ajax send 우리가 보낸다. 우리가 보내고 싶을때 보낸다.) callback은 언제 호출될까? 우리가 통제할 수 없는 시간에 함수가 ‘떵’하니 호출된다.
'아잇, 야 나 아직 그거 받을 준비 안되었는데?, 왜 벌써 보내?'
, '야 이거 아직도 안왔냐?'
이렇게 된다. 그래서 우리의 코드가 헬이 된다..
저쪽에선 이미 데이터를 보냈는데 받을준비 또는 그릴 준비가 안되어 있다던지.
callback 타임을 항상 조종해야한다. callback을 받아서 어떻게 하나? ‘받을 준비가 완료 되었으면 뿌려, 아니면?’ 아니면 어떡하나? 또 루프를 돌고 있어야한다. timer로, interval로.. 받을 준비 다 될때까지 기다려야 하니까..
이 문제 어떻게 해결하나? 해결 못하기에 callback hell이 만들어지는 것이다. 복잡성을 통제할 수 있는 능력이 없다.
그럼 어떻게 해야하나? Promise는 우리에게 반 제어권을 준다. 반 제어권이란, 우리가 promise의 then을 호출하고 싶을때 호출 할 수 있는 것이다. promise 객체를 만드는 순간 비동기가 시작된다. promise then을 언제 호출할지는 우리가 결정할 수 있다.
promise 객체를 변수에 쥐고 있다가, then을 우리가 호출하고 싶을때 호출할 수 있다. 우리에게 제어권이 온 것이다.
근데 이건 절반의 제어권이다. 왜냐하면 then을 호출하자마자 그 함수가 호출 되고 안되고가 그때그때 다르기 때문이다.
promise가 resolve된 상태라면, promise는 안에 resolve된 값을 쥐고 있고, 우리가 then을 호출할 때 까지는 쥐고 있을 것이다. 함부로 callback을 발동시키지 않는다. 하지만 우리가 then을 호출했는데도 아직 resolve된 상태가 아니라면, 우리가 then을 호출했지만 기다리긴 해야한다. 반 제어권
이다.
비동기여서 완전 제어권을 가질수는 없으니까 반제어권을 주겠다는 것이다. then을 네가 원할때 호출할 수 있게 해줄게.
이것만으로, then의 연쇄가 일어난다. 우리가 원할때 then을 호출하면, 이 안에서 다시 promise를 실행하면 이 promise의 then도 우리가 원할때 실행할 수 있다.
그럼 이제부터 우리는 어떤 함수가 동기형으로 리턴값을 반환하는 대신에 promise객체를 리턴하는것 만으로, 우리가 원할때 return값을 then할 수 있게 된다. 비동기 함수가 값을 리턴할 수 있게 된 것이다.
이제 객체들은, 함수들은, 모든것들은 자기가 비동기적으로 움직일 때도 리턴값을 줄 수 있게 된것이다. 그전에는 callback이여서 리턴값을 줄 수 없었다. 이제는 결과처리할 때 리턴 받은 promise를 우리가하고 싶을때 then한다.
반제어가 우리에게 넘어오는 것이 큰 차이이다.
아주 쉽게 정리를 하자면, 프로시저형으로만 짯던 비동기 함수를 반제어권으로 인해 리턴값을 주는 함수로 짤 수 있게 된 것이다.
출처: https://www.youtube.com/watch?v=bqHPOYzoBE&list=PLBNdLLaRxrKT18ivygZ7Jmi_4h5zb2wv&index=4