항해 99

항해 99 12주차를 끝내며

세발낙지 2022. 4. 4. 03:59

   이번 주에는 promise에 대한 이야기를 조금 적어볼까 한다. Javascript는 논 블로킹 IO를 채택한 언어로 다른 블로킹 IO 언어처럼 한줄 한줄 읽어나가며 실행 코드가 콜 스택에 쌓이고, 이것이 하나씩 하나씩 실행하는 구조로 이루어져 있다. 다만, 비동기 code를 만날 경우, 이런 코드들을 백그라운드로 넘기고, 백그라운드에서 실행이 되어 콜백 큐에 쌓인다. 테스크 큐에 쌓인 동작들은 콜 스택이 빌 경우, 콜 스택으로 이동하여 실행되게 되고, 이 과정은 콜백 큐에 쌓인 동작들이 모두 완료될 때까지 반복된다. 이것을 이벤트 루프라고 하는데, 이런 이벤트 루프가 작동하기 때문에 Javascript에서는 손쉽게 비동기 코드를 작성할 수 있는 큰 장점이 있다. 

    

    내가 promise에 대해서 오해했던 것이 있다. Promise의 경우, 별다른 처리를 하지 않더라도 백그라운드에서 실행되고, 콜스택이 비어있을 때 이벤트 루프가 동작하여 콜백 큐에서 콜 스택으로 이동하게 되는데, 나는 then이나 catch 같은 promise의 종료와 관련있는 코드가 작성되었을 때에만 그렇게 작동한다고 오해했다. 이것은 promise에 대해서 이해하기 위해서 나름의 실험을 해보던 와중에 알게 된 것이었은데, 그 코드는 다음과 같다.

// 원래는 이런식으로 then이나 catch 등의 프로미스의 작동이 끝나야
// 작동하는 코드가 존재하는 경우에면 정상적으로 작동할 것으로 생각했다.

let a = new Promise((resolve, reject) => {
  setTimeout(() => { resolve(console.log(3)) }, 1000)
}).then((value) => console.log(value)).catch((error) => console.log(error))

    이런 식으로 then이나 catch를 만나면 promise에 대한 evaluation이 작동되고, 콘솔에 로그가 나올 것으로 생각했다. 실제로 위 코드는 evaluation 과정에서 console.log(3)에 의해 3이 출력되고, 그 이후 then에서 console.log가 return하는 undefined를 받아서 undefined가 출력된다. 그러나, 이렇게 then이나 catch를 작성하지 않아도 3이 출력되는 가에 대해서 한번 실험을 해보았는데, 결과가 나에게는 신기했다. 

// 이런 경우에도 정상적으로 콘솔에 3이 출력되는 것을 확인했다.

let a = new Promise((resolve, reject) => {
  setTimeout(() => { resolve(console.log(3)) }, 1000)
})

    Promise는 then 등의 코드를 만나지 않더라도 evaluation이 이루어지며, then 등이 필요한 것은 promise가 resolve되고 나서 전달된 값이 필요한 경우에만 그런 것 같았다. 추가적으로 이런저런 실험을 해보며 또 새로운 것을 찾았는데, 그 코드는 다음과 같다.

 

// 또 하나 신기한 사실을 발견했는데, 아래와 같이 작성할 경우, reject를 만나 에러를 발생시키며
// 실행이 종료되고, 출력이 아예 없을 것으로 생각했다.
// 그러나, 신기하게 3이 출력되었다.

let a = new Promise((resolve, reject) => {
  setTimeout(() => { reject(1), resolve(console.log(3)) }, 1000)
})

    이런 식으로 reject를 만나게 될 경우, resolve로 넘어가지 않고 바로 종료되고 error를 발생시키며 1을 전달할 것으로 생각했지만, 콘솔에 3이 출력되는 것을 확인했다. reject를 만나더라도 백그라운드에서 코드가 바로 종료되지 않고, 끝까지 evaluation을 진행하는 것으로 된다. 

 

    추가적으로 아래와 같이 코드를 작성할 경우, resolve를 하며 넘길 값도 계산되고, reject를 통해 .catch로 값이 정상적으로 넘어가는 것을 확인할 수 있었다. 실행 결과는 3이 출력되고, 1이 출력되었다. 

// 아래와 같이 작성할 경우에도 .catch 안에 
// 실제 실행 결과는 resolve 안에 있는 console.log(3)이 작동하며 3이 먼저 출력되고, 
// 그 후에 .catch가 작동하여 1이 출력되었다는 것이다.
// 물론, .then은 작동하지 않았지만, reject를 만나도 resolve 안에 있는 값을 evaluation한다는 
// 것이 신기했고, promise에 대해서 더 공부하고 싶어졌다.

let a = new Promise((resolve, reject) => {
  setTimeout(() => { reject(1), resolve(console.log(3)) }, 1000)
}).then((value) => console.log(value)).catch((error) => console.log(error))

 

    아래와 같이 코드를 작성할 경우, resolve를 먼저 만나기 때문에 then 이하의 코드가 실행되지만, reject에 대한 evaluation 역시 실시되기 때문에 3과 2가 출력되고, undefined가 출력된다. catch 이하의 코드가 작동되었으면 undefined + 1의 결과인 NaN이 출력되었을 것이지만, 출력되지 않았다. 순서를 바꿀 경우에는 2, 3 그리고 NaN이 출력되는 것을 확인할 수 있었다. 

// .catch 이하의 코드가 작동된다면, NaN이 출력되겠지만, 출력되지 않았다.

let a = new Promise((resolve, reject) => {
  setTimeout(() => { resolve(console.log(3)), reject(console.log(2) + 1) }, 1000)
}).then((value) => console.log(value)).catch((error) => console.log(error))

 

    백엔드 서버를 만들다 보니 클라이언트에 결과는 최대한 빨리 전송하고 싶고, 할 일은 많을 때 중요하지 않은 일은 그냥 백그라운드에서 실행하면 되지 않을까 하는 생각에서 이것저것 찾아보다 보니 프로미스는 아주 흥미로운 객체인 것 같다. 알림 등과 같은 부분은 웹에서 그렇게 실시간성을 요구한다고 생각하지 않아서 이런 부분은 비동기인 체로 그대로 내버려두고 작성하면 어떨까 고민 중에 있다. 또한, 복잡한 쿼리문을 작성하다보니 MySQL에 대한 공부가 부족한 점이 너무 깊게 와닿는 것 같다. 항해가 끝나면 책을 구입하여 진득하게 읽어보고 싶다. 

'항해 99' 카테고리의 다른 글

항해 99 11주차를 끝내며  (0) 2022.03.28
항해 99 10주차를 끝내며  (0) 2022.03.21
항해 99 9주차를 끝내며  (0) 2022.03.15
항해 99 8주차를 끝내며  (0) 2022.03.07
항해 99 7주차를 끝내며  (0) 2022.02.28