자바스크립트는 기본적으로 동기적으로 작동합니다. 하지만 자바스크립트는 여러개의 비동기 메소드를 지원하여 사용자에 이벤트나 HTTP 응답에 반응할 수 있도록 만들어 졌습니다.
사용자의 행동은 언제 발생할지 예측하는 것은 매우 복잡한 문제이며 실제로 그런 방법은 많지 않습니다. 그렇기 때문에 특정 이벤트에 종속되어 있거나, HTTP 응답등을 기다려야 하는 경우에, 우리가 알고있는 동기 프로그래밍(Syncronous Programming)은 매우 비효율 적인 방식입니다.
비동기 프로그래밍은 어떤 일이 완료되기를 기다리지 않고 다음 코드를 실행해 나가는 프로그래밍 방식입니다. 반대로 어떤 일이 완려될 때까지 코드의 실행을 멈추고 기다리는 프로그래밍 방식을 동기식 프로그래밍(Synchronous Programming)이라고 부릅니다.
브라우저에서의 비동기 프로그래밍은 주로 통신과 같이 오래 걸리는 작업들을 브라우저에 위임할 때 이루어집니다.
비동기 프로그래밍 방식은 대게 프로그래밍 성능과 응답성을 높이는 데에 도움을 줍니다. 하지만 코드가 실제로 실행되는 순서가 뒤죽박죽이 되므로, 코드의 가독성을 해치고 디버깅을 어렵게 만든다는 비판을 받아왔습니다. 이런 문제를 해결하기 위해 비동기 프로그래밍을 위한 여러 기법이 생겨났고, 또 어떤 것들은 JavaScript언어 자체에 포함되기도 했습니다. 여기에서는 근래 JavaScript 생태계에서 자주 사용되는 몇 가지 비동기 프로그래밍 기법들을 살펴 보겠습니다.
콜백은 다른 함수의 인수로 넘기는 함수를 말하는데, 이 콜백을 가지고 비동기 프로그래밍을 할 수 있습니다.
아래 예제는 유명한 JavaScript 라이브러리인 JQuery를 이용해 Github의 Create-react-app 프로젝트에 등록되어 있는 이슈 목록을 가져와서 출력하는 코드입니다.
const $ = require('jquery');
const API_URL = "https://api.github.com/repos/facebookincubator/create-react-app/issues?per_page=10";
$.ajaxSetup({
dataType: 'json'
});
$.get(API_URL, issues => {
console.log('최근 10개의 이슈:');
issues
.map(issue => issue.title)
.forEach(title => console.log(title));
console.log('출력이 끝났습니다.');
});
console.log('받아오는 중...');
위 예제에서 $.get
메소드의 두 번째 인수로 콜백을 넘겨주었습니다. $.get
메소드는 비동기식으로 동작하며, Github API 서버와 통신하는 일을 브라우저에 위임한 후 바로 종료됩니다. 통신이 끝나면, 그 결과를 첫 번째 인수로 해서 콜백을 호출하게 됩니다.
여기서 주의할 것은 콜백을 인수로 받는 함수가 항상 비동기식으로 동작하는 것은 아니라는 것입니다. 위 예제의 map
, forEach
의 인수로 넘겨준 것 역시 콜백이지만 이 때에는 콜백이 동기식으로 호출됩니다. 즉, 콜백의 실행이 끝날때 까지 코드의 실행 흐름이 다음으로 넘어가지 않습니다.
콜백은 JavaScript가 고차함수를 잘 지원한다는 특징으로 인해 가장 많이 사용되는 비동기 프로그래밍 양식이었습니다. 하지만 콜백만으로는 복잡한 비동기 데이터 흐름을 표현하기가 어려워서 많이 프로그래머들이 힘들어 했고 결국, 콜백 지옥(Callback Hell) 이라는 용어까지 생겨났습니다.