TIL#41 JS) 자바스크립트의 비동기

luneah·2021년 12월 11일
0

JavaScript

목록 보기
14/16
post-thumbnail

JavaScript

자바스크립트는 동기적인 언어이고, blocking 이며, single-threaded 한 언어이다. 이것은 한번에 한번의 작업만 진행할 수 있다는 특성을 의미한다. 하지만 자바스크립트의 모든 것에서 이러한 특성을 의미하지는 않는다.

만약 많은 양의 데이터 베이스를 요청해야 한다면 어떻게 할까? 동기적으로 처리한다면 하나의 작업에 대한 요청을 하고 응답을 기다리는 동안 다른 작업은 대기해야 할 것이다. 그렇게 되면 작업을 처리하는데 시간이 굉장히 오래 걸린다.

자바스크립트는 이러한 이슈를 해결하기 위해 해결책을 제시했다. 사람들이 자바스크립트가 비동기적 언어라고 오해하는 이유가 자바스크립트를 비동기적으로 동작하도록 할 수 있기 때문이다.

자바스크립트의 비동기 처리

특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 자바스크립트의 특성을 의미한다.

비동기적으로 처리하는 경우

  • Ajax Web API 요청 : 서버 쪽에서 데이터를 받아와야 하는 경우
  • 파일 읽기 : 서버에서 파일을 읽어야 하는 경우
  • 암호화/복호화 : 바로 처리 되지 않고, 시간이 어느정도 걸리는 경우
  • 작업 예약 : setTimeout을 사용하여 비동기 처리하는 경우

1. Callback

Callback 함수는 특정 함수에 매개변수로 전달된 함수를 의미한다. 콜백 함수는 함수를 전달받은 함수 안에서 호출된다.

동기 처리에서 가장 간단한 해결책은 비동기 Callback을 사용하는 것이다.

function Callback(callback){
    console.log('콜백 함수');
    callback();
}
Callback(function(){
    console.log('콜백 받는곳');
})

함수의 반환 값을 받은 다음 비동기 처리를 해야 하는 경우에 위와 같은 함수를 콜백으로 받아 비동기 처리를 할 수 있다.

하지만 콜백 함수는 가독성이 매우 떨어지고 그렇기 때문에 실수할 위험도 커진다. 비동기 처리가 아래처럼 3개로 끝나지 않는다면 끝없이 옆으로 누운 피라미드를 그리게 된다.

function Callback(callback){
    function Callback2(callback){
        function Callback3(callback){
            console.log('무한콜백');
        }
    }
}

이러한 무한콜백을 해결하기 위해 ES7에서는 Promise를 지원하고 ES8에서는 async / await를 지원한다.

2. Promise

Promise는 자바스크립트에서 비동기 작업을 좀 더 편리하게 처리 할 수 있도록 ES6에 도입된 기능으로 Callback이 하는 일과 같은 역할을 한다.

차이점은 프로미스는 작업이 끝난 후 실행할 함수를 제공하는 것이 아니라 자체 메소드인 .then()을 호출한다. 또한 .then()과 같은 메소드를 연속적으로 사용이 가능한 이점이 있어 코드를 작성하고 이해하기가 쉬워진다.

const promise = new Promise ((resolve, reject) => {
	//executor 실행자, 실행 함수.. 
})

resolve는 new Promise가 만들어 질때 자동으로 실행된다. executor의 인수 resolve, reject는 자바스크립트가 자체적으로 제공하는 콜백이다.

  • resolve : 작업이 성공적으로 끝난 경우, 그 결과를 나타내는 value와 함께 호출한다.
  • reject : 에러 발생 시 에러 객체를 나타내는 error와 함께 호출한다.

executor는 자동으로 실행되는데 여기서 원하는 일이 처리된다. 처리가 끝나면 성공 여부에 따라 resolve나 reject를 호출한다.

Promise의 3가지 상태

프로미스는 3가지의 상태(states)를 가지며, 여기서 상태란 프로미스의 처리 과정을 의미한다. new Promise()로 프로미스를 생성하고 종료될 때까지 3가지 상태를 가진다.

  1. Pending : 비동기 처리 로직이 아직 완료되지 않은 상태 (대기)
  2. Fulfilled : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태 (성공)
  3. Rejected : 비동기 처리가 실패하거나 오류가 발생한 상태(실패)

성공하면 .then()메소드가 실행되고, 실패하면 reject를 사용하고, error는.catch()메소드를 사용해서 처리한다.

Promise에서의 예외 처리

add10(10)
  .then((res) => {
        throw 'test error';
    })
  .catch((err) => console.log(err));

promise에서는 작업이 실패했을 경우 자동으로 .catch()메소드를 호출되게 한다. 기존 try-catch를 이용해서도 예외처리가 가능하지만 자바스크립트에서는 promise의 catch를 사용하라는 warning message를 출력한다.

3. async/await

async/await는 ES8 문법으로서 promise를 기반으로 하는 가장 최근에 나온 문법이다. 이를 사용하면 보다 쉽게 비동기적인 상황을 표현할 수 있다.

async function 함수명(){
 await 비동기처리_메서드명();
}

Async와 Await을 사용하려면 우선 사용할 함수 앞에 async라는 키워드를 붙여 사용해야 하며 선언된 async 함수 안에서만 await 키워드를 사용할 수 있다.

await은 함수의 작업이 끝나고 결과값을 반환할 때까지 대기하게 되며 결과 값이 리턴된다면 다음 작업으로 넘어가게 된다.

  • async
    async 는 function 앞에 위치한다. function 앞에 async 를 붙이면 해당 함수는 항상 promise 를 반환한다.

  • await
    await 을 만나면 promise 가 처리될 때까지 기다린다. 결과는 그 이후에 반환된다. 일반 함수에는 사용할 수 없다. async 함수가 아닌데 await 을 사용하면 문법 에러가 발생한다. 위에도 말했듯이 await 은 async 함수에서만 발생한다.

async/await 의 예외 처리

  1. .catch()를 이용하여 예외처리를 할 수 있다.
async function f1() {
  const a = await add10(10).then(res => res);
  const b = await add10(a).catch(err => err);
  console.log(a, b);
}
f1();

// f1은 promise를 리턴하므로 promise가 지원하는 메소드 사용 가능
  1. 기존방식인 try-catch도 사용 가능하다.
async function f2() {
  try {
    const a = await add10(10);
    const b = await add10(a);
    console.log(a, b);
  } catch(err) {
    console.log(err);
  }
}
f2();
profile
하늘이의 개발 일기

0개의 댓글