본문 바로가기

javascript Deep Dive

[JavaScript] Callback 함수

콜백함수

- 다른 코드의 인자로 넘겨주는 함수

=> 자바스크립트에서 함수는 자료이므로 변수에 할당이 가능, 함수를 함수의 매개변수로 전달해서 활용가능

이렇게 매개변수로 전달하는 함수를 콜백함수라고 한다.

 

콜백함수를 왜 사용할까?

콜백함수를 사용하는 이유를 이해하려면 먼저 자바스크립트의 런타임 동작원리를 알아야한다.

자바스크립트는 싱글스레드를 사용하는데, 멈춤을 방지해준다.

블로킹을 방지하여 싱글스레드가 논블로킹으로 동작하게 한다.

=> 자바스크립트에서 비동기적 프로그래밍이 가능하게 한다

 

자바스크립트 런타임

자바스크립트의 런타임 요소는 JavaScript 엔진/ Web API/ 이벤트 루프/ 콜백큐(태스크 큐)가 존재한다

 

동작순서

 

1. 함수는 CallStack에 LIFO순서로 쌓여서 진행된다.

2-1. 함수에 콜백함수가 있을때 JS내부에서 처리가능하면 CallStack에 쌓인다.

2-2. JS내부에서 처리가 불가능하면(비동기API) WepAPI에게 위임한다.

3. WebAPI는 비동기 API 실행 후 콜백함수를 Callback Queue에 삽입한다.

4. Event Loop는 Call Stack이 비었을 때 Call back Queue에서 콜백함수를 빼서 Call Stack에 넣어준다.

5. Call Stack에 올라간 콜백함수를 POP되어 실행된다.

 

Web API

 

- Web API는 브라우저나 nodejs에서 제공되는 API, AJAX나 Timeout등의 비동기 작업을 실행한다.

- 자바스크립트에서 setTimeout 함수같은 함수를 실행 -> JS엔진은 WepAPI에 setTimeout을 요청하고 동시에 setTimeout에 넣은 Callback까지 전달한다

- 받은 setTimeout을 완료하고 Callback을 Callback Queue에 넘겨준다.

 

Callback Queue && Event Loop

 

- Callback Queue는 Wep API에서 넘겨받은 Callback을 큐형태로 저장한다.

- Callback 함수들은 자바스크립트 엔진의 CallStack의 모든 작업이 완료되면 순서대로 CallStack에 추가한다.

- 이때 Event Loop는 Call Stack이 비어있는지 아닌지 (실행중인 작업이 존재하는지)와 Callback Queue에 Task가 존재하는지 판단, Queue의 작업을 Call Stack에 옮긴다.

 

JS는 자체적으로 비동기 API를 처리하지 못한다. 대신 JS의 런타임 구성요소 WepAPI를 통해 비동기 API처리를한다. 즉, JS는 WepAPI에게 비동기 API 처리를 위임하고 다른일을 처리한다.

 

콜백함수의 사용 유형

1. 익명함수 사용

 

- 콜백함수는 이름 없는 '익명의 함수'를 사용한다. 함수의 내부에서 실핸되기 때문에 이름을 붙이지 않아도 된다.

 

2. 함수의 이름(만) 넘기기

 

- 자바스크립트는 함수를 변수 또는 다른 함수의 변수처럼 사용할 수 있다(1급함수). 함수를 콜백함수로 사용할 경우, 함수의 이름만 넘겨주면 된다.

 

3. 전역변수, 지역변수를 콜백함수의 파라미터로 전달 가능

 

- 전역변수 : 함수 외부에서 선언된 변수

- 지역변수 : 함수 내부에서 선언된 변수

 

콜백함수의 주의할 점

콜백지옥

 

- 콜백 지옥은 콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들정도로 깊어지는 현상이다.

- 주로 이벤트 처리나 서버 통신과 같은 비동기적인 작업을 수행하기 위해 이런 형태가 자주 등장하는데, 가독성이 떨어지면서 코드를 수정하기 어려워진다.

- 비동기적인 작업을 수행하기 위해 콜백함수를 익명함수로 전달하는 과정에서 생기는 콜백 지옥을 Promise, async/await, Generator 등을 사용해 방지할 수 있다.

 

Promise

- 프로미스는 자바스크립트 비동기 처리에 사용되는 객체이다.

- 싱글스레드인 자바스크립트에서 비동기 처리를 위해 사용한 Callback 함수의 에러/예외처리의 어려움, 중첩으로 인한 복잡도 증가라는 단점을 해결하기 위해 프로미스 객체를 ES6에서 언어적 차원으로 지원한다.

 

Promise가 콜백을 대체하는 것은 아니지만, 콜백을 예측 가능한 패턴으로 사용할 수 있게 하며 Promise없이 콜백만 사용했을 때 예상치 못한 동작을 막아주거나 찾기 힘든 버그를 상당 수 해결해준다.

 

const promise = new Promise((resolve, reject) => {
	/*
    	비동기 작업 성공시 resoleve()를 호출하고,
        비동기 작업 실패시 reject()를 호출하도록 구현한다.
    */
})

 

Promise 성공 시 resolve를 호출하고 실패 시 reject를 호출한다.

 

const promise = new Promise((resolve, reject) => {
	// 처리 내용
})

promise.then(
	// resolve가 호출되면 then이 실행
)
.catch(
	// reject가 호출되면 catch가 실행
)
.finally(
	// 콜백 작업을 마치고 무조건 실행되는 finally(생략가능)
)

 

- Promise 다음엔 then() 과 catch()를 사용한다.

- then()은 생성한 프로미스 객체에서 인수로 전달한 resolve가 호출되면 실행된다.

- catch()는 생성한 프로미스 객체에서 인수로 전달한 reject가 호출되면 실행된다.

 

- then()과 catch() 뒤에는 또다른 then()과 catch()를 연결함으로써 비동기 처리를 연결할 수 있다.

 

Promise의 3가지 상태

- 프로미스의 상태란 프로미스의 처리 과정을 의미한다.

- new Promise()로 프로미스를 생성하고 종룔될 때 까지 3가지 상태를 갖는다.

1. Pending(대기) - 비동기 처리 로직이 아직 완료되지 않은상태

2. Fulfilled(이행) - 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태

3. Rejected(실패) - 비동기 처리가 실패하거나 오류가 발생한 상태

 

Promise의 에러 처리 방법

1. then()의 두 번째 인자로 에러를 처리하는 방법

2. catch() 를 이용하는 방법

 

=> Promise의 에러 처리는 catch()를 이용하는 것이 효율적이다.

 

async & await

- async & await는 비동기식 코드를 동기식으로 표현하여 간단하게 나타내는 것.

- 기존의 비동기 처리 방식인 Callback 함수의 단점을 보완하기 위해 Promise 를 사용했지만, 코드가 장황하다는 단점이 존재한다.(콜백지옥)

- 이러한 단점을 해결하기 위해 ES2017(ES8)에서 도입된 비동기 처리 방식의 가장 최신 문법이다

- async & await 는 Promise 객체를 반환한다 ( => then을 사용할 수 있다.)

 

async & awit 기본 문법

async function 함수명() {
	awit 비동기메서드()
}

 

- 함수의 앞에 async 라는 예약어를 붙인다.

- 함수의 내부 로직 중 HTTP 통신을 하는 비동기 처리 코드 앞에 await를 붙인다.

 

try...catch문으로 예외처리를한다

'javascript Deep Dive' 카테고리의 다른 글

[JavaScript] prototype  (0) 2023.12.23
[JavaScript] 클로저(Closure)  (0) 2023.12.22
[JavaScript] This  (0) 2023.12.22
[JavaScript] 실행 컨텍스트  (2) 2023.12.21
[JavaScript] 데이터 타입  (0) 2023.12.21