JavaScript

[JS] 동기/비동기/콜백/promise/async/await

효진인데요 2023. 8. 16. 21:41

 

 

 

0. 동기 

 

 

 

 

  • 동기적 처리 (Synchronous)
  • 순차적 실행
  • 서버에 요청을 보냈을 때 응답이 돌아온 뒤 다음 동작을 수행
  • A 작업이 모두 진행되어 마칠 때까지 B 작업은 대기

 

 

ex.

 

console.log('first');
console.log('second');
console.log('third');

/*
first
second
third
*/

 

 

위와 같이  코드를 작성한 뒤 실행되는 결과를 확인해 보면

위에서부터 한 줄씩 내려오며

하나의 작업이 완전히 끝난 뒤 다음 코드가 차례로 실행되는 것을 확인할 수 있다.

이를 동기적 처리 방식이라고 한다.

 

 

 


 

 

 

1. 비동기

 

 

 

  • 비동기적 처리 (Asynchronous)
  • 서버에 요청을 보냈을 때 응답 상태와 관계 없이 다음 동작 수행 가능
  • A 작업이 시작되면 동시에 B 작업 실행 시작
  • 특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 자바스크립트의 특성

 

 

ex.

 

console.log('first');
setTimeout(() => {
console.log('second');
}, 1000);
console.log('third');

/*
first
third
second
*/

 

 

 

위 코드에서는 간단한 비동기 처리 방식의 순서를 확인하기 위해 setTimeout 함수를 사용했다.

 

setTimeout 함수의 첫 번째 인자는 콜백 함수, 두 번째 인자는 지연 시간으로 0을 주었다.

 

코드가 동작하는 과정을 한 줄 한 줄 보면,

  1. console.log('first');를 만나 콘솔에 first를 찍는다.
  2. setTimeout() 메소드를 만나 이 메서드를 처리하는 다른 프로그램에 전송한다.
  3. console.log('third'); 줄로 이동해 콘솔에 third를 찍는다.
  4. setTimeout() 메소드를 처리하는 프로그램은 비동기를 제외한 모든 동기적 코드가 실행된 뒤 결과를 콘솔에 찍는다.

 

이렇게 무작정 위에서부터 한줄씩 읽으며 찍는 것이 아니라는 것을 확인할 수 있다.

 

 

 


 

 

 

 

2. JS에서 비동기 코드를 처리하기 위한 방법

 

2.1 Callback 함수 

 

  • JS에서는 함수를 인자로 받고 다른 함수를 통해 반환되는 것이 가능한데, 이때 인자로 대입되는 함수
  • 다른 함수가 실행이 끝난 뒤 실행되는 함수
  • 함수를 선언할 때, 인자로 함수를 받아서 사용 가능
  • 비동기 방식으로 작성된 함수를 동기 방식처럼 순서대로 실행할 수 있도록 만들 수 있다.
    (하지만, 코드는 여전히 비동기적으로 동작)

 

function mainFunc(param1, param2, callbackFunc) {
    // ... 처리 내용 작성
    callbackFunc(result);
}

 

 

기본적인 콜백 함수의 형태이다.

 

보통 함수를 선언한 뒤 함수 타입 파라미터를 가장 마지막에 하나 더 선언해 주는 방식으로 정의한다.

동기 방식으로 작성된 코드의 처리가 끝나면 파라미터로 전달 받은 함수를 실행한다.

( + 필요한 경우 결과 값을 인자로 넘겨줄 수도 있음 )

 

 

 

 

 

콜백 지옥 ( Callback Hell )

 

출처:구글이미지

 

 

  • 비동기 프로그래밍 시 발생 가능성 있는 문제
  • 콜백 함수를 익명 함수로 전달하는 과정에서 또 다시 콜백 안에 함수 호출이 반복
    ▶ 코드의 들여쓰기가 너무 깊어지는 현상
  • 가독성이 낮아지는 동시에 코드 수정 난이도가 높아짐

 


 

 

2.2 Promise

 

  • 비동기 함수를 동기적으로 처리하기 위해 만들어진 객체
  • 성공 / 실패를 분리하여 반환
  • 비동기 작업이 완료된 뒤, 다음 작업을 연결시켜 진행할 수 있음
  • 최종 결과를 반환하는 것 X ▶ 미래의 어떤 시점에 결과를 제공하겠다는 '약속'을 반환

 

 

 

promise의 상태

 

 

출처:https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise

 

 

  1. Pending (대기) : Promise를 이행하지도, 거부하지도 않은 초기 상태 / 수행하지 않은 상태
  2. Fulfilled (이행) : Promise가 Resolve (성공) 된 상태
  3. Rejected (거부) : Promise가 지켜지지 못한 / Reject (실패) 된 상태
  4. Settled : Fulfilled 혹은 Rejected로 결론이 난 상태

 

 

 

Promise Chaining (프로미스 체이닝)

 

  • 프로미스 체이닝은 코드를 더 효율적으로 짜기 위해 사용됨
  • 비동기 코드를 매우 간단하게 정리할 수 있음
  • then 메서드를 연속적으로 사용하여 순차적인 작업이 가능
  • 여러 개의 프로미스 체인 중 하나라도 rejected 상태가 되면 가장 마지막에 달린 catch 문으로 이동하여 에러를 처리
    ▶ 나머지 프로미스를 하나하나 차례로 확인하는 불필요한 작업 X

 

 

 

new Promise(function(resolve, reject) {

  setTimeout(() => resolve(1), 1000); // (*)

}).then(function(result) { // (**)

  alert(result); // 1
  return result * 2;

}).then(function(result) { // (***)

  alert(result); // 2
  return result * 2;

}).then(function(result) {

  alert(result); // 4
  return result * 2;

});

 

 

위 코드의 실행 순서를 보면,

 

  1. 1초 뒤 첫 번째 프로미스 함수가 실행 // (*) 부분
  2. 첫 번째 .then 핸들러 호출  // (**) 부분
  3. 2에서 반환한 값은 다음, then 핸들러로 전달  // (***) 부분
  4. 더 있는 경우 이러한 과정 반복

result 값은 alert 창에 1, 2, 4가 차례로 출력됨.

 

 

출처:https://ko.javascript.info/promise-chaining

 

 

 


 

 

 

2.3 Async Await

 

  • 가장 최근에 나온 방법
  • promise chaining을 하다보면 then 함수가 많아져 꼬리를 물게 되어 코드의 가독성 저하 가능
  • 보다 직관적인 코드
  • 따로 새로운 기능 추가 된 것 X ▶ promise를 다르게 사용하는 것

 

 

async await
function 앞에 위치 프로미스 앞에 위치
프로미스가 아닌 값을 반환해도 이행 상태의 프로미스로 값을 감싸서 해당 프로미스 반환 프로미스가 모두 실행되어 처리될 때까지 대기
비동기로 실행되는 것이 있음을 알림 프로미스가 모두 처리되면 결과를 마지막에 반환
async가 붙은 함수는 항상 promise 반환 await는 async 함수 안에서만 동작

 

 

 

 

728x90