일단 확실하게 알아둬야 할 것은!!!
자바스크립트는 싱글스레드 논블록킹 비동기 동적언어다!
sync
: 결과 나오면 바로 씀
async
: 결과 나와도 바로 안씀 (항상 Promise 반환)
blocking
: 상대가 작업할동안 난 멈춤
non-blocking
상대가 작업할때 나도 계속 작업함
자바스크립트에서 async는 대개 async nonblocking
그래서 둘 개념 헷갈리는 경우가 왕왕 있다.
https://bakjuna.tistory.com/94?category=955668도 같이 읽음
(대충 네모로 쳐둔 것은 시간이 지나가고 있다는 뜻..)
순서:
hello
0a
0c
0pepe
2000b
500test2
500d
0test3
-> 모든 값이 나올 때 까지는 약 3000초가 소요된다.
(사이 숫자는 소요 시간, 컴퓨터 연산속도 바로바로 나오는건 임의상 0초라고 함)
순서:
hello
0a
0c
2000b
1000d
0pepe
2500test2
0test3
-> 약 5500초가 소요된다.
이 상태가 Blocking이 되었다는 것!
await 위치 하나가 바뀌었을 뿐인데..!
JavaScript programmers like to use words like, “event-loop”, “non-blocking”, “callback”, “asynchronous”, “single-threaded” and “concurrency”.
We say things like “don’t block the event loop”, “make sure your code runs at 60 frames-per-second”, “well of course, it won’t work, that function is an asynchronous callback!”
If you’re anything like me, you nod and agree, as if it’s all obvious, even though you don’t actually know what the words mean; and yet, finding good explanations of how JavaScript actually works isn’t all that easy, so let’s learn!
With some handy visualisations, and fun hacks, let’s get an intuitive understanding of what happens when JavaScript runs.
블로킹에 대한 설명: 7:48
https://link.medium.com/UZ5JHbgbotb 여기 글 읽으면 잘 나옴
그 외 참고 문서
https://choar816.tistory.com/190?category=981984
https://velog.io/@yejineee/이벤트-루프와-태스크-큐-마이크로-태스크-매크로-태스크-g6f0joxx
https://link.medium.com/oLafo2Aaotb
예전에 필기해뒀던 내용 여기 글로 합쳤음 (위에 이벤트 루프 영상을 보고나서 다시 읽으니까 더 이해가 잘 됨)
개인 공부용으로 쓰는 것이고 정확하지 않으니 참고사이트를 위주로 보시길 바랍니다
그림 출처, 참고사이트
https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke
https://ko.javascript.info/event-loop
html 공식 문서에서 이벤트 루프 관련 문서 보기: https://html.spec.whatwg.org/multipage/webappapis.html
비동기
의 오해
1. 비동기는 동시의 문제가 아니다! 순서의 문제다
setTimeout(() => {
console.log("a");
}, 0);
setTimeout(() => {
console.log("b");
}, 1000);
setTimeout(() => {
console.log("c");
}, 2000);
Promise.resolve().then(() => {
console.log("p");
});
이 코드를 출력하면 다음과 같이 출력된다
p
a
b
c
이때!!
첫번째 "a" 를 출력하는 SetTimeout 과 "p"를 출력하는 Promise가 맞짱까면 Promise가 이긴다. 왜 그럴까?
왜냐하면 SetTimeout()
은 macro 큐에, Promise
는 micro 큐에 쌓이는데, micro 큐가 우선순위가 높기 때문이다!
그림에서 직관적으로 보이듯이 모든 함수는 스택이 비워질 때마다 하나씩 쌓여서 실행되고 pop되고 난 후에 또 하나씩 콜스택으로 올라가는데, micro 큐가 먼저 콜 스택으로 올라가서 실행된다.
그런 다음 콜스택과 micro큐가 둘 다 비었을 경우, 이벤트루프는 macro 큐에 task가 있는지 확인하고 실행한다.
마이크로 큐에 해당하는 메서드는 외워두는 것이 좋다.
참고:
마이크로태스크 큐 == 잡 큐
매크로태스크 큐 == 이벤트 큐 or 콜백 큐로 불리기도 한다.
쓸데없는 궁금증:
만약 Macro 큐에 있는 메서드끼리 비교했을 때, 뭐가 먼저인지 알고싶다면.. nodejs 공식문서 를 참고해보자. 근데 어차피 실무에서 setTimeout()
이 먼저냐 setImmediate()
이 먼저냐를 굳이 따질 일이 잘 없다고 한다. 최대한 그런 상황을 피하는 것이 좋고 애초에 같은 함수에 집어넣으면 되는 것을 굳이 그런 식으로 설계를 하지 않는다고 한다.
(주의: 정확하지 않다. 한글문서니 당연히 믿거하시겠지만, 내가 이해하기로는 그렇다고 해서 거기까지는 파고가지 않을 생각이다. 게다가 나는 저 부분까지는 아직 이해하기에는 한참 남은 것 같다.)
promise
: 실행은 바로 하긴 하는데 결과값을 나중에 내가 원할 때 얻을 수 있는 것
console.log("start");
setTimeout(() => {
console.log("time out!");
}, 0);
Promise.resolve("Promise!").then((res) => console.log(res));
console.log("End!");
console.log("start"); 출력
setTimeout() 콜스택에서 popped 된 후 WEB API 이동
The setTimeout method is native to the browser: its callback function (() => console.log('In timeout')) will get added to the Web API
-> 시간 완료 이후 macro task에 추가됨
Promise.resolve() 콜스택 추가
resolve 되고 then의 콜백 함수는 microtask queue에 추가됨
console.log("End!"); 출력
V8 엔진은 콜스택이 비었다는 것을 확인한 후 큐에 뭐가 있는지를 확인한다.
microtask queue 우선 실행 후 마지막으로 macrotask queue 실행
이 강의 보면서 필기: https://youtu.be/A7AeQzEoEmc
let a = 2;
const p = new Promise((resolve, reject) => {
// Promise 내부는 동기 코드임
console.log("This string comes out first!");
setTimeout(() => {
console.log("a");
let a = 5;
resolve(a);
}, 0);
});
console.log("test");
p.then((result) => {
console.log("result", result);
});
This string comes out first!
test
a
result 5
실행순서
console.log("This string comes out first!");
출력console.log("test")
출력나머지 Web API로 넘어간 비동기 부분이 남았음!
setTimeout(() => {
console.log("a");
let a = 5;
resolve(a);
}, 0);
console.log("a")
출력p.then((result) => {
console.log("result", result);
});
console.log("result", result);
콜스택으로 올라간 후 출력-> 스택, 큐 모두 텅 비었음! 자바스크립트 종료
(cf. setInterval 같은 경우에는 계속 web api에 남아서 실행됨 ~ clearInterval로 직접 꺼줘야함)
이벤트루프가 왜 있는가? 에 대한 근본적인 해답은 https://youtu.be/0NsJsBdYVHI 에서 타임라인 1:21:13 참고!
참고사이트: https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke
자바스크립트에서는 다른 작업에 의존하는 작업을 다룰 때가 있다.
예를들면 사진을 하나 얻고 싶다 할 때
사진을 압축하고 -> 압축된 이미지에 필터를 입히고 -> 그 이미지를 저장한다
이걸 코드로 구현하면 콜백지옥
이 펼쳐진다.
http://callbackhell.com/
완전 가독성도 구리고 의존적이라서 별루임
ES6에서 Promise 등장!!
"A promise is a placeholder for a value that can either resolve or reject at some time in the future"
Promise
는 status를 갖고있는 객체이다.
쉬운 영어 부분은 그냥 갖구 오고 어려운 부분만... 해석해야지
The value of the PromiseStatus, the state, can be one of three values:
✅ fulfilled: The promise has been resolved. Everything went fine, no errors occurred within the promise 🥳
❌ rejected : The promise has been rejected. Argh, something went wrong..
⏳ pending: The promise has neither resolved nor rejected (yet), the promise is still pending.
this callback function actually receives two arguments.
The value of the first argument, often called resolve
or res
, is the method to be called when the Promise should resolve.
The value of the second argument, often called reject
or rej
, is the value method to be called when the Promise should reject, something went wrong.
.then(): Gets called after a promise resolved.
.catch(): Gets called after a promise rejected.
.finally(): Always gets called, whether the promise resolved or rejected.
코드를
이렇게 극복!!
The result of the .then itself is a promise value. This means that we can chain as many .thens as we want: the result of the previous then callback will be passed as an argument to the next then callback!
https://ko.javascript.info/async-await
https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/async%20&%20performance/README.md#you-dont-know-js-async--performance
https://eslint.org/docs/latest/rules/no-return-await
https://stackoverflow.com/questions/43353087/are-there-performance-concerns-with-return-await
return await promise
and return promise