View

콜백 함수는 다른 코드의 인자로 넘겨 주는 함수입니다. 어떤 함수 X를 호출하면서 인자로 콜백 함수 Y를 넘겨 주었다고 하면, 함수 X는 특정 조건일 때 Y를 호출하게 됩니다. 이처럼 콜백 함수는 다른 코드에게 인자로 넘겨줌으로써 그 제어권을 함께 위임한 함수입니다. 콜백 함수를 위임받은 코드는 자체적인 내부 로직에 의해 이 콜백 함수를 적절한 시점에 실행합니다.

 

콜백 함수는 함수다

콜백 함수로 어떤 객체의 메서드를 전달하더라도 그 메서드는 메서드가 아닌 함수로서 호출됩니다.

var obj = {
	vals: [1, 2, 3],
        logValues: function(v, i) {
		console.log(this, v, i);
        }
};

// (1)
obj.logValues(1, 2); // { vals: 1, 2, 3], logValues: f} 1 2
// (2)
[4, 5, 6].forEach(obj.logValues); // Window { ... } 4 0

(1)번의 경우 logValues 메서드의 이름 앞에 점이 있으니 메서드로서 호출했습니다.

(2)번의 경우 obj를 this로 하는 메서드를 그대로 전달한 것이 아니라, obj.logValues가 가리키는 함수만 전달했습니다. 이 함수는 메서드로서 호출할 때가 아닌 한 obj와의 직접적인 연관이 없어집니다. 따라서 this는 다른 콜백 함수들과 같이 전역 객체를 바라보게 됩니다.

 

콜백 지옥과 비동기 제어

동기적인 코드는 현재 실행 중인 코드가 완료된 후에야 다음 코드를 실행하는 방식입니다.

반대로 비동기적인 코드는 현재 실행 중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어갑니다. 

사용자의 요청에 의해 특정 시간이 경과되기 전까지 어떤 함수의 실행을 보류한다거나(setTimeout), 사용자의 직접적인 개입이 있을 때 비로소 어떤 함수를 실행하도록 대기한다거나(addEventListener), 웹브라우저 자체가 아닌 별도의 대상에 무언가를 요청하고 그에 대한 응답이 왔을 때 비로소 어떤 함수를 실행하도록 대기하는 등(XMLHttpRequest), 

별도의 요청, 실행 대기, 보류 등과 관련된 코드는 비동기적인 코드입니다.

 

콜백 지옥은 콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어지는 현상으로, 자바스크립트에서 흔히 발생하는 문제입니다.

자바스크립트 진영은 비동기적인 일련의 작업을 동기적으로, 혹은 동기적인 것처럼 보이게끔 처리해 주는 장치를 마련하고자 끊임없이 노력했습니다.

 

1. Promise

new 연산과 함께 호출한 Promise 객체의 인자로 넘겨 주는 콜백 함수는 호출할 때 바로 실행되지만, 그 내부에 resolve 또는 reject 함수를 호출하는 구문이 있을 경우 둘 중 하나가 실행되기 전까지는 then 또는 catch 구문으로 넘어가지 않습니다.

 

2. Generator

*이 붙은 Generator 함수를 사용할 수 있습니다. Generator 함수를 실행하면 Iterator가 반환되는데, Iterator는 next라는 메서드를 가지고 있습니다. 이 next 메서드를 호출하면 Generator 함수 내부에서 가장 먼저 등장하는 yield에서 함수의 실행을 멈춥니다. 그러니까 비동기 작업이 완료되는 시점마다 next 메서드를 호출해 준다면 Generator 함수 내부의 소스가 위에서부터 아래로 순차적으로 진행될 것입니다.

 

3. async / await

비동기 작업을 수행하고자 하는 함수 앞에 async를 표기하고 함수 내부에서 실질적인 비동기 작업이 필요한 위치마다 await를 표기하는 것만으로도 뒤의 내용을 Promise로 자동 전환하고, 해당 내용이 resolve 된 이후에야 다음으로 진행합니다.

export const test1 = async() => {
	let value = await 1
	console.log(value) // 1
	value = await Promise.resolve(1)
	console.log(value) // 1
}

export async function test() {
	let value = await 'hello'
	console.log(value) // hello
	value = await Promise.resolve('hello')
	console.log(value) //hello
}

// anync 함수를 일반 함수처럼 사용한 예
// 두 함수가 마치 동시에 실행된 것처럼 보인다.
test1()
test2() // 실행 결과 1 \ hello \ 1 \ hello

// async함수를 Promise 객체로 사용한 예
test1()
	.then(() => test2()) // 실행 결과 1 \ 1 \ hello \ hello
Share Link
reply
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30