동기식 처리가 뭐냐면 한번에 코드 한줄씩 차례차례 실행된다는 소리이다
자바스크립트를 실행하는 웹브라우저는 stack이라는 코드 실행 공간이 있는데
거기서 코드를 한줄한줄 차례로 실행한다
<script>
console.log(1);
console.log(2);
console.log(3);
</script>
///1,2,3이 출력이 된다.
예상하신 대로 1,2,3이 차례로 출력된다
왜냐면 자바스크립트는 한번에 코드 한줄씩 차례차례 실행되기 때문.
이걸 전문용어로 동기적이다~ (synchronous) 라고 할 수 있다.
대부분의 프로그래밍 언어들은 이런 특징을 가지고 있다.
특정 코드를 1초 후에 실행하고 싶으면 어떻게 할까?
일반적인 프로그래밍 언어에서 이런 코드를 작성하려면......
print(1)
time.sleep(1)
print(2)
///파이썬
time.sleep(1)이라는건 1초 쉬어주세요 라는 뜻이다.
그럼 1이라는게 출력되고 / 1초 쉬고 / 2라는게 출력되는걸 볼 수 있다.
자바스크립트에서 1초 쉬고 뭔가 출력하는 코드를 작성하려면
console.log(1);
setTimeout(function(){}, 1000);
console.log(2);
보통 프로그래밍 언어처럼 이렇게 작성하면 될까?
안됩니다. 1과 2가 콘솔창에 동시에 출력되는걸 볼 수 있다.
여기서 자바스크립트의 이상한 점을 느낄 수 있다.
자바스크립트는 보통 프로그래밍 언어들과 생각하는 방식자체가 다르다.
왜그러냐면 setTimeout()
이라는 함수를 잘 보시면 이건 실행까지 시간이 조금 걸리는 함수이다.
1초나 걸린다.
자바스크립트 실행머신인 웹브라우저는
이런 특수한 코드들을 발견하면 약간 제쳐두고 다른 코드부터 실행하려고 합니다.
그래서 setTimeout() 을 제껴두고 그 밑에 있는
console.log(2)라는 코드 부터 실행하는 것
이런 처리방식을 바로 비동기(asynchronous)라고 한다.
실행이 오래걸리는 그런 코드들은 잠깐 *대기실(태스크 큐) 에 제쳐두고,
실행이 바로바로 가능한 코드들부터 처리하는 방식을 뜻한다.
이건 자바스크립트 언어 자체의 기능이 아니라
자바스크립트 실행을 도와주는 웹브라우저 덕분에 해낼 수 있는 것이다.
실행을 미루고 옆으로 잠깐 제껴둘 수 있는 코드들은 미리 정해져있다.
위에서 말했던 setTimeout, addEventListener, ajax 관련 함수들이 바로 그것이다.
setTimeout, addEventListener, ajax관련 함수들은 1초대기, 클릭대기 이런걸 하는 코드들인데
이런 코드들의 특징은.. 읽는 시점과 동작 시점이 차이가 있다. (쉽게 말하면 동작까지 오래걸린다.)
자바스크립트를 실행하고 해석하는 브라우저는 이런 특별한 코드들을 만나면
잠깐 대기실에 제껴두고
준비가 완료되면 다시 실행시킨다.
console.log(1);
setTimeout(function(){}, 1000);
console.log(2);
브라우저는 위의 코드를 읽다가 setTimeout~ 이런 코드를 만나면 잠시 Web API 대기실로 옮겨서 대기 시킨다
1초의 대기시간이 지나고 setTimeout이 완료가 되면 대기실에서 코드를 꺼내서 코드가 실행되게 만들어준다.
이것 덕분에 setTimeout같이 시간이 오래걸리는 코드들을 비동기식으로 처리할 수 있는 것이다.
한마디로.
그래서 자바스크립트는 평소에 별일 없으면 동기식으로 처리하는데
비동기를 지원하는 setTimeout 같은 함수를 이용하면 비동기식으로 동작하게 만들 수 있는 언어이다.
그럼 아까 예시로 돌아와서, 자바스크립트에서 1초 후에 코드를 실행하고 싶으면 어떻게 할까?
console.log(1);
setTimeout(function(){
console.log(2);
}, 1000);
console.log(3);
저렇게 setTimeout 안에 콜백함수안에 코드를 짜면 된다
그러면 콘솔창에 1과 3이 먼저 빠르게 출현하고
그 다음 1초 후에 2라는 숫자가 출현한다.
자바스크립트는 비동기상황 등에서 코드를 순차적으로 실행하고 싶을 때 콜백함수를 적극 활용한다.
콜백함수가 뭔데요?
함수안에 들어가는 함수를 전부 콜백함수라고 부른다.
예를 들면 순차적으로 실행하고 싶은 함수가 두개 있으면,
그럼 이렇게 코드짜면 될까?
function 첫째함수(){
console.log(1)
}
function 둘째함수(){
console.log(2)
}
첫째함수();
둘째함수();
파이썬으로 코드짜신다면 이게 맞다.
하지만 자바스크립트는 비동기라는 특수성으로 인해 이렇게 쓴다고 순차적으로 실행하는걸 보장하진 않는다.
(첫째함수가 뭐 setTimeout이라든지 Web API 대기실로 보내는 코드라면 나중에 실행될 수 있으니까)
콜백함수를 만들어서 첫째함수(둘째함수);
이런 식으로 실행시킬 수 있게 만들어놓으면 순차적으로 실행할 수 있.
그럼 어떻게 코드를 짜놔야 함수를 함수안에 집어넣을 수 있을까?
function 첫째함수(콜백){
console.log(1);
콜백();
}
function 둘째함수(){
console.log(2)
}
첫째함수(둘째함수);
함수에 파라미터를 하나 뚫어주시면 된다..
그리고 그 파라미터에 소괄호를 붙여서 호출하면 함수안에 함수를 집어넣어서 실행이 가능합니다.
이게 콜백함수 디자인하는 법이다
다른방법으로는
첫째함수(function(){
console.log(2)
}):
이렇게 직접 함수선언문을 집어넣을 수도 있다.
순차적으로 실행하려고 콜백함수를 여러개 사용하면 단점이 있다.
코드가 옆으로 길어지며 가독성이 좋지않다.
첫째함수(function(){
둘째함수(function(){
셋째함수(function(){
어쩌구..
});
});
}):
이런거 보기싫기에 ES6 신문법인 Promise라는 문법을 만들어 사용하시면 된다.
콜백대신 쓸 수 있는 Promise 디자인 패턴을 적용하면 어떻게 되냐면
첫째함수().then(function(){
그 담에 실행할거
}).then(function(){
그 담에 실행할거
});
옆으로 길어지지 않고 then이라는 메소드 덕분에 그나마 뭘 하는지도 파악이 쉬워진다.