-
[TIL] Day 33. 비동기 처리와 콜백함수IT 지식 2020. 11. 20. 19:54728x90
이번에 새롭게 노드를 공부하게 되었습니다. 그런데 노드를 공부하기에 앞서 promise에 대한 개념이 필요하다고 하더군요. 그래서 promise에 대해 공부하려고 보니, 이번엔 사전 지식으로 비동기 처리와 콜백함수에 대한 개념이 필요하다는 것을 알게 되었습니다(개발의 세계는 끝이 없어라...). 그래서 오늘은 제가 공부한 비동기 처리와 콜백함수에 대한 개념을 정리해보는 시간을 가져보도록 하겠습니다.
1. 비동기 처리가 뭔가요?
비동기 처리란 특정 코드의 실행이 끝날 때까지 다른 코드들이 대기하며 기다리는 것이 아니라, 계속해서 코드를 읽어 나가며 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 자바스크립트의 특성을 의미합니다.
console.log('1') console.log('2') console.log('3') // 실행결과 // 1 // 2 // 3
위의 코드는 동기적으로 처리된 코드의 예시 입니다. 코드가 순차적으로 실행이 되면서 다른 코드들이 앞선 코드가 완료 될 때까지 기다리고 있는 것을 알 수 있습니다.
console.log('1') setTimeOut(console.log('2'), 1000) console.log('3') // 실행결과 // 1 // 3 // 2
반면 위의 코드는 비동기적 코드의 예시 입니다. 코드가 순차적으로 읽히기는 하지만 실행된 결과값은 순차적이지 않죠. 맨 처음 1이 불러와진 후에 setTimeOut으로 결과값이 1초 뒤에 불러와지는 동안 그 뒤 코드인 3이 실행되고 나서 2가 불러와졌습니다.
왜 이런 현상이 발생하는 것일까요?
만일 모든 코드가 동기적으로 이루어진다면, 많은 양의 데이터를 서버에서 불러와야하는 코드들이 있는 경우에 사용자는 서버와의 통신이 끝날 때까지 빈 화면을 기다려야 할 것입니다. 주고 받아야 하는 코드의 양이 크기 때문이죠. 하지만 비동기적으로 코드를 실행한다면, 우선 빠르게 처리할 수 있는 함수들을 실행하고 그 후에 불러온 데이터를 활용하여 페이지를 꾸밀 수 있겠죠. 즉, 비동기적인 처리는 사용자가 대기해야 하는 시간을 단축해주고 UX적 측면에서 보다 나은 환경을 제공하기 위한 특성이라고 할 수 있습니다.
2. 콜백지옥과 Promise의 등장
1) 콜백지옥
하지만 모든 코드가 비동기적으로 이루어질 수는 없습니다. 예를 들어 로그인 시, 아이디와 패스워드를 입력하고, 그 값이 서버와 일치하는지 확인한 후 로그인 토큰을 받아서 사이트에 접속해야하는 경우가 있습니다. 그때에는 아이디와 패스워드를 확인하는 동안 사용자를 사이트에 접속시키면 안되기 때문에 반드시 함수는 순차적으로 처리되어야 합니다. 이때 함수를 순차적으로 진행시키는 방식이 콜백함수 입니다.
doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log('Got the final result: ' + finalResult); }, failureCallback); }, failureCallback); }, failureCallback); //출처: https://velog.io/@yejinh/%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0
위의 함수가 콜백지옥의 예시라고 볼 수 있습니다. 다양한 기능들이 반드시 순차적으로 진행되어야 할 때, 위와 같은 방식으로 콜백함수를 중첩적으로 계속 불러오는 것입니다. 위의 함수처럼 콜백함수가 세번만 불러져도 이미 가독성이 많이 떨어지게 되는데, 만약 함수의 구조가 이것보다 복잡해진다면 가독성은 컴퓨터가 아니고서는 제대로 이해하지 못할 수준으로 떨어지게 될 것입니다(솔직히 그정도라면 컴퓨터도 이해 못할지도...). 또 콜백함수에 대한 에러 처리를 각각의 함수에서 설정해주어야 하기 때문에 개발자 입장에서도 일이 너무나도 많아지게 됩니다. 모두가 불행한 상황에 직면하게 되는 것이죠.
2) Promise
이런 비극적인 결말을 피하고자 ES6에서는 Promise라는 새로운 객체를 만들어냅니다. Promise의 상태값은 다음의 네 가지를 가집니다.
Pending: 아직 결과 값이 반환되지 않은 진행 중인 상태 Settled: 결과 값이 성공 혹은 실패로 반환된 상태 fulfilled: 성공 Rejected: 실패
이때 유의해야 할 사항은 한번 Settled 된 값은 재실행할 수 없다는 것입니다.
Promise는 함수를 인자로 받으며, 그렇게 인자로 들어온 함수는 resolve와 reject 2개의 함수를 인자로 받게 됩니다. resolve 는 비동기 처리를 성공했을 때 호출되는 함수이며, reject는 비동기 처리가 실패했을 때 호출되는 함수입니다.
const promise = new Promise(function(resolve, reject) { setTimeout(function() { res(111); }, 1000); }); // 화살표 함수의 경우 const promise = new Promise((resolve, reject) => { setTimeout(() => { res(111); }, 1000); }); // 출처: https://velog.io/@yejinh/%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0
이렇게 생성된 Promise 객체는 then과 catch로 그 값을 받아오게 됩니다. 성공한 경우(resolve)에는 then으로 그 값을 받게 되고, 실패한 경우(reject)에는 catch로 그 에러 처리를 하게 됩니다.
const promise = new Promise((res, rej) => { setTimeout(() => { res(111); }, 1000); }); promise .then(res => console.log(res)); // 출력값 111 const promise = new Promise((res, rej) => { setTimeout(() => { rej('error!'); }, 1000); }); promise .then(res => console.log(res)) .catch(err => console.error(err)); // catch 메소드에 잡혀서 console.error에서 출력된 값 error! //출처: https://velog.io/@yejinh/%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0
이때 중요한 점은 then 메소드는 다시 Promise 객체를 반환한다는 것입니다. Promise 객체가 반환되기 때문에 다시 then과 catch를 쓸 수 있으며 다수의 then을 통해 Promise chaining을 가능하게 한다는 점입니다.
3) async / await
async / await 구문은 Promise를 좀 더 편하게 사용하기 위한 방법으로 async를 통해 함수를 선언하면 해당 함수는 Promise 객체에 담기게 된다. await 는 특정 함수가 settled 된 후에 resolve 된 값을 할당하게 해줍니다(코드 진행을 기다린다고 생각하시면 됩니다).
console.log(0); function promise() { console.log(1); return new Promise(resolve => { setTimeout(() => { console.log(2); resolve('resolved'); }, 2000); }); } console.log(3); async function asyncCall() { try { console.log(4); const result = await promise(); // Promise가 settled될 때까지 기다린 후 resolve된 값을 할당한다. console.log(result); console.log(5); } catch(err) { console.error(err); // error 발생 시 catch 블락에서 잡히도록 handling } } console.log(6); asyncCall(); // 출력 값 0 3 6 4 // asyncCall 호출 1 // promise 함수 호출 2 // 2초 후 setTimeout 콜백 함수 호출 resolved // resolve함수 호출 5 // await 후 다음 코드 실행 //출처: https://velog.io/@yejinh/%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0
이런 식으로 함수를 작성하게 되면 콜백지옥에 빠지지 않고 함수들을 동기적으로 실행할 수 있게 됩니다.
3. 마무리
오늘은 자바스크립트의 특징인 비동기처리와 비동기처리를 동기적으로 처리할 수 있게 해주는 Promise에 대해 알아보았습니다. 제가 경험한 코딩의 세계에서는 아직 Promise를 적극적으로 활용해야하는 경우가 많이 없었지만, 이제 곧 경험하게 될 node의 세계에서는 자주 쓰인다고 하니, Promise에 대해 더 공부하고 익히면서 node를 자유자재로 쓸 수 있도록 연습해야겠습니다.
728x90'IT 지식' 카테고리의 다른 글
[TIL] axios 사용법 (0) 2020.11.29 [what is?] node.js 가 뭔가요? (0) 2020.11.22 [TIL] Day 32. export default의 의미에 대해 (0) 2020.11.17 [TIL] Day 31. git rebase 하는 법 (0) 2020.11.15 [what is?] git이 뭔가요? (0) 2020.11.15