WEB/🌳 Node.js

[Node.js] 4. 동기 / 비동기

무딘붓 2022. 7. 28. 17:18

 

1. 동기(Synchronous)와 비동기(Asynchronous)

 

Node.js의 특징은 비동기 처리를 고려해서 만들어졌다는 점이다.

그렇다면 동기는 뭐고 비동기란 무엇일까?

출처 : https://medium.com/@vivianyim/synchronous-vs-asynchronous-javascript-de4918e8ad62

- 동기(Synchronous)

 

동기는 한번에 한가지 작업을 하는 것으로, 앞의 작업이 끝나야 다음 작업으로 넘어가는 방식이다.

자세히 설명하면 요청을 보낸 후, 요청에 대한 응답을 받아야 다음 작업을 실행하는 것이다.

일반적인 많은 프로그램이 이와같은 방법으로 실행된다.

 

- 비동기(Asynchronous)

 

비동기는  요청을 보낸 후, 응답에 상관 없이 다음 동작을 실행하는 것이다.

즉, 다음 동작을 실행하고 있을 때, 앞의 동작이 끝나지 않았으면 앞의 동작과 함께 다음 동작이 실행된다.

 

 

비동기 작업의 효율성을 알기 위해 A(실행시간 10초), B(실행시간 500초), C(실행시간 20초)라는 작업이 있다고 가정하자.

A,B,C라는 작업이 순서대로 주어졌을때, 실행에 필요한 시간을 비교해보면

 

동기로 실행할 때는 A 10초 → B 500초 → C 20초 순서대로 실행되어 총 530초가 걸린다.

비동기로 실행할 때는 A,B,C 동시에 실행되어 A는 10초, C는 20초만에 끝나고, 마지막으로 500초가 걸린 B가 실행되면 총 500초만에 작업이 끝난다.

동기, 비동기 실행 예시

 

위의 예시에서는 큰 차이가 나지 않아보이지만, C의 실행이 완료되는 시간을 비교하면 차이가 크다.

동기로 실행할 때는 A,B가 모두 끝난 시점(510초)에 C의 실행이 시작되어 C의 실행이 끝나는 시점은 530초다.

반면, 비동기로 실행하는 경우 C의 실행이 완료되는 시간은 20초다.

 

Node.js는 이러한 비동기 처리를 고려하기때문에 I/O(입출력) 속도가 빠르다는 장점이 있다.

하지만 장점이 있으면 단점도 있는 법이다. 단점에 대해서는 Node.js에서의 비동기 처리를 살펴보며 알아보자.


2. 예시로 살펴보는 비동기의 이해

 

사실 자바스크립트에서 자주 쓰이는 내장 함수에도 비동기 함수가 있다.

 setTimeout(콜백함수, 지연시간(밀리초) );

setTimeout()은 콜백함수와 지연시간을 인자로 받아서, 지연시간이 지나면 콜백함수를 실행한다.

이때, setTimeout()은 비동기로 실행되는데, 이를 확인하기 위해 아래 예시를 살펴보자.

function two() {
    console.log(2);
}

console.log(1);
setTimeout(two, 1000);
console.log(3);

 

비동기적으로 실행되는 setTimeout()

동기적인 실행이라면

[     '1' 출력   →   (1000ms = 1초 후)2 출력   →   3 출력     ] 이겠지만,

위의 실행 결과를 보면

[     '1' 출력   →   '3' 출력   →   ('1' 출력 1초 후) '2' 출력     ] 순서임을 확인 할 수있다.

이는 setTimeout이 실행되는 동안, 다음 작업들이 setTimeout()이 끝나기를 기다리는 것이 아니라 setTimeout()의 종료와 상관 없이 순차적으로 실행되었다는 것을 보여준다.

 


 

3. Node.js에서의 동기와 비동기

 

Node.js에서 동기와 비동기를 비교하기위해 파일을 읽어들이는 함수를 살펴보자.

var fs = require('fs');

fs.readFileSync(path)		// 동기
fs.readFile(path, callback)	// 비동기

동기적으로 파일을 읽어들이기 위해서는 readFileSync()를 사용하고, 비동기적으로 읽을 때는 readFile()을 사용한다.

아래 예시를 살펴보자.

var fs = require('fs');

// 동기(Synchronous)
console.log(1);
var result1 = fs.readFileSync('./two.txt', 'utf8')
console.log(result1);
console.log(3);

///////////////////////////////////////////////
console.log('---------');
///////////////////////////////////////////////

// 비동기(Asynchronous)
console.log(1);
fs.readFile('./two.txt', 'utf8', function (err, result) {
    console.log(result);
})
console.log(3);

실행결과
앞서 살펴본대로, 동기적 실행인 readFileSync()의 경우와 비동기적 실행인 readFile()의 결과가 다른 것을 볼 수 있다.

 

함수의 사용방법에도 차이가 있는데, 일반적인 함수처럼 반환값을 반환하는 readFileSync()와 달리, readFile()은 반환값이 없고, 실행이 끝났을 때 콜백함수에 반환값을 인자로 받아서 실행하는 것을 볼 수 있다.

 

이와같이 비동기적 실행은 콜백함수를 사용하게 만들고, Node.js는 비동기 처리를 자주 사용하기 때문에 콜백함수를 더 많이 사용하게 되어 굉장히 복잡한 코드가 만들어지기도 한다. 이것이 '콜백 지옥'이라고 부르는 Node.js의 단점이기도 하다.