티스토리 뷰

개발 언어/NodeJS

비동기 프로그래밍

jin-park 2020. 1. 11. 19:14

동기(synchronous) 및 비동기(asynchronous)

동기 방식

- 하나의 요청이 처리되는 동안 다른 요청이 처리되지 못하며 요청이 완료되어야만 다음 처리가 가능한 방식. (ex. java)

비동기 방식

- 하나의 요청 처리가 완료되기 전에 제어권을 다음 요청으로 넘겨 Blocking 되지 않으며 다음 요청을 처리 하는 방식. (ex. nodejs)

NodeJS

  • 비동기 IO를 지원하며 Single-Thread 기반으로 동작하는 서버.
  • 클라이언트의 요청을 비동기로 처리하기 위하여 이벤트가 발생하며 Event Loop가 처리.
  • Event Loop가 처리하는 동안 제어권은 다음 요청으로 넘어가고 처리가 완료되면 Callback을 호출하여 처리완료를 호출측에 알려준다.

  • 올바른 사용 환경
    • 각 단위 작업이 아주 짧은 시간 안에 처리된다면 Node.js의 고성능의 병렬 처리의 장점을 극대화 함.
    • 올바른 비동기 프로그래밍 방식으로 개발을 진행해야함.
  • 올바르지 못한 사용 환경
    • CPU를 많이 사용하는 처리 작업이나 대용량 파일을 처리하는 작업.
    • 동기 방식의 개발 진행.

동기 방식 프로그래밍

자바와 같은 프로그래밍 방식으로 위에서 아래로 진행되어진다.

위에서 설명했다시피 nodejs는 single thread이므로 동기 방식으로 작성할 경우 nodejs의 이점은 없어지므로 주의해서 사용한다.

var fs = require('fs');
 
console.log('start');
 
var filenames = fs.readdirSync('.');
var i; 
for (i = 0; i < filenames.length; i++) { 
    console.log(filenames[i]);
}
 
console.log('end');
 
// 실행 결과: start -> filenames -> end

비동기 방식 프로그래밍

콜백 방식

  • 자바 스크립트에서 함수는 일급 객체이므로 파라미터로 넘길 수 있음.
    • 일급 객체란?
      • 변수나 데이터에 할당 가능.
      • 객체의 인자로 넘길수 있음.
      • 리턴값으로 사용 가능.
  • 실행 결과를 보면 비동기로 수행되는것을 알수 있음.
  • 위의 전달된 콜백 함수는 디렉토리를 모두 읽은 후 호출됨으로써 비동기 프로그래밍이 가능해짐.
let fs = require('fs');
 
console.log('start');
 
fs.readdir('.', (err, filenames) => {
  if (err) {
    console.error(err);
    return;
  }
  
  for (let i = 0; i < filenames.length; i++) {
    console.log(filenames[i]);
  }
});

console.log('end');
 
 
// 실행 결과: start -> end -> filenames

Promise 방식

  • 복잡한 처리에서는 위의 콜백 방식을 사용할 경우 콜백 헬 발생
  • 비동기 작업을 콜백에 비해 쉽게 컨트롤 가능, 비교적 가독성이 좋음.
  • 오류 처리를 가시적으로 대응할 수 있음.
const fs = require('fs');

function readDirPromise() {
  return new Promise((resolve, reject) => {
    fs.readdir('.', function (err, filenames) {
      err ? reject(err) : resolve(filenames);
    });
  });
}

readDirPromise()
  .then(function (filenames) {
    console.log('filenames - ', filenames);
  })
  .catch(function (error) {
    console.log('error - ', error);
  });

Generator 방식

const fetch = require('node-fetch');

// 외부 api를 사용한다.
function getUser(generatorObject, username) {
  fetch(`https://api.github.com/users/${username}`)
    .then(res => res.json())
    .then(user => {
      // user 이름을 줄테니까 다음을 실행시켜!
      generatorObject.next(user.name)
    });
}

let main;

// 비동기 함수가 포함되어있는 메인함수
function* mainFunction() {
  let user;

  // getUser를 실행하고 멈춰있어!
  user = yield getUser(main, 'jessie');
  console.log('1user - ', user);
  user = yield getUser(main, 'kevin');
  console.log('2user - ', user);
  user = yield getUser(main, 'albert');
  console.log('3user - ', user);
}

// iterator 함수 반환
main = mainFunction();
// main 함수 실행
main.next();

async/await 방식

  • async, await 는 ES8(ECMAScript2017)의 공식 스펙(링크)
  • promise, generator보다 더욱 절차적(동기적)인 프로그래밍 방식으로 개발가능
(async () => {
    try {
        const filenames = await fs.readdir('.');
        for (let i = 0; i < filenames.length; i++) {
            console.log(filenames[i]);
        }
    } catch (e) { console.error(e); }
})();

이벤트 루프

https://namjackson.tistory.com/30


출처

'개발 언어 > NodeJS' 카테고리의 다른 글

NodeJS - WebRTC  (0) 2020.02.28
NodeJS - Socket IO  (0) 2020.02.28
자바스크립트 - 프로토타입 상속  (0) 2019.12.03
자바스크립트 - ES6문법  (0) 2019.07.27
자바스크립트 - 객체  (0) 2019.07.27
댓글