JavaScript - callback 과 promise

치맨·2023년 2월 20일
0

javascript

목록 보기
15/23
post-thumbnail

목차

콜백함수란

  • CallBack 함수란 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 의미합니다.

  • 함수 안에서 실행하는 또 다른 함수 라고 할 수 있습니다.


콜백함수 사용 이유

  • 첫째 : 함수에서 반복적인 일은 변하지 않고, 공통적으로 수행하지만, 반복하면서 하는 일의 내용은 다르게 처리를 할 수 있습니다. 만약 콜백함수가 없다면 매번 함수를 새롭게 정의 해야 합니다.

    • 예를들어 1부터 입력받은 숫자까지의 모든 숫자를 합하는 함수가 있습니다.

    • 이때 입력받은 숫자 중 홀수만 더하는 함수, 입력받은 숫자 중 짝수만 더하는 함수를 구현할려고 할때 콜백함수를 사용하지 않는다면
      1. 모든수를 더하는함수, 2.짝수를 더하는함수, 3. 홀수를 더하는 함수 총 3가지의 함수를 구현해야 합니다.

    • 하지만 콜백함수를 사용한다면 변하지 않는 부분은 그대로 두고, 변하는 부분만 처리를 할 수 있습니다.

  • 둘째 : 함수를 굳이 정의하지 않고 익명 함수로도 전달 가능합니다.

  • 셋째 : 비동기(Asynchronous) 처리 방식(이벤트 처리, Ajax통신, 타이머 함수 등)에 중요하게 사용됩니다.


콜백함수 단점

  • 첫째 : 콜백함수를 너무 남용하면 코드의 가독성이 떨어집니다. (콜백 지옥)

  • 둘째 : 에러 처리가 어렵습니다.

  • 셋째 : 여러개의 비동기 처리를 한번에 하는데도 한계가 있습니다.

  • 아래의 사진에서 우선 딱봐도 가독성이 아주 떨어집니다. 또한 try, catch를 통해 error가 잡히지 않습니다.

비동기가 아닌경우 : 에러가 잡힌경우 아래와 같이 출력됩니다.


Promise란

  • 위에서 언급한 콜백함수의 단점을 극복하기 위해 ES6에서 Promise가 도입되었습니다.

  • Promise는 호스트 객체가 아닌 ECMAScript 사양에 정의된 표준 빌트인 객체입니다.

  • 프로미스는 비동기 처리 상태와 처리 결과를 관리하는 객체입니다.

  • Promise는 크게 생성, 처리를 합니다.


promise 생성

  • new 연산자와 함께 호출하여 Promise객체를 생성합니다.

  • Promise생성자 함수는 executor 함수라고 부르는 콜백함수를 전달받는데 이 함수는 resolve, reject 함수를 인수로 받습니다. executor 콜백함수 = resolve,reject를 가지고 있다.

    • executor 함수 : ()=>{}
    • resolve, reject : executor 함수 내부에 있는 것 (resolve, reject)=>{}
  • resolve : 콜백함수로 비동기 처리가 성공할 경우 resolve함수에 비동기 처리 결과를 인수로 전달하여 호출합니다.

  • reject : 콜백함수로 비동기 처리가 실패하면 reject함수에 에러를 인수로 전달하여 호출합니다.

  • 상태정보 : Promise는 비동기 처리가 어떻게 진행되고 있는지를 나타내는 상태(state)정보를 갖습니다.

  • settled 상태 : pending이 아닌 상태, 즉 fullfiled 이거나 rejected인 상태
    => 비동기 처리가 수행 된 상태

  • 상태정보의미상태 변경 조건
    pending비동기 처리가 아직 수행되지 않은 상태프로미스가 생성된 직후 기본상태
    fulfilled비동기 처리가 수행된 상태(성공)resolve 함수 호출
    rejected비동기 처리가 수행된 상태(실패)reject 함수 호출

Promise 처리

  • 프로미스 비동기 처리 상태가 변하면 후속 처리를 해야한다.

    • 프로미스가 fulfilled 상태, 즉 성공하면 처리 결과(data)로 무엇을 처리해야한다.
    • 프로미스가 rejected 상태, 즉 실패하면 처리 결과(에러)로 에러 처리해야한다.
  • 프로미스는 후속처리 메서드인 then, catch, finally를 제공합니다.

then

  • then : 두개의 인자를 받고, 언제나 프로미스를 반환하며, 비동기로 동작합니다.

    1. 첫번째 인자는 fulfilled 상태(resolve 함수가 호출된 상태)가 되면 호출됩니다.

    2. 두번째 인자는 rejected 상태(reject 함수가 호출된 상태)가 되면 호출됩니다. 그러나 두번째 인자로 받은 경우 첫번째 콜백함수에서 발생한 에러를 캐치하지 못하고, 코드가 복잡해져서 가독성 또한 좋지 않습니다.
      ==> 따라서 에러처리는 두번째 인자로 사용하기 보다는 catch메서드를 통해 사용 하는 것이 좋습니다.


catch

  • catch : 한개의 인수로 전달받으며, 프로미스가 rejected상태인 경우만 호출됩니다.
    => 즉 에러 발생한 경우만 사용

  • finally : 한개의 인수로 전달받으며, 성공 또는 실패와 상관없이 한번만 호출됩니다.
  • 주로 프로미스 상태와 상관없이 공통적으로 수행해야 할 처리 내용이 있을때 유용합니다.

Promise Chaining

  • 만약 후속처리 메서드의 콜백함수가 promise 아닌 값을 반환하더라도 그 값을 암묵적으로 resolve, reject하여 프로미스를 생성해 반환하기 때문에 언제나 Promise를 반환합니다.

  • 따라서 언제나 Promise를 반환하기 때문에, 연속적으로 사용할 수 있습니다. 이를 promise-chainig이라고 합니다.

  • Promise는 promise chaining을 통해 비동기 처리 결과를 후속 처리 하므로 비동기 처리를 위한 콜백 패턴에서 발생하던 콜백헬이 발생하지 않습니다. 다만 콜백 패턴을 사용하기 때문에 콜백함수를 사용하지 않는 것은 아닙니다.

  • 콜백패턴은 가독성이 좋지 않기 때문에 이를 해결하기 위해 ES8에서 도입된 async/await 사용하여 Promise 후속처리 메서드 없이 동기 처럼 처리 결과를 반환하도록 구현할 수 있습니다.


async, await

  • 위에서도 언급했지만, async, await는 가독성 좋게 비동기 처리를 동기처리처럼 동작하도록 구현할 수 있습니다.

  • async 함수

    • async 키워드를 사용해 정의하며, 언제나 프로미스를 반환합니다.

    • 명시적으로 프로미스를 반환하지 않더라도 async 함수는 암묵적으로 반환값을 resolve하는 프로미스를 반환합니다.

    • 클래스의 constructor 메서드는 async메서드가 될 수 없습니다.
      왜 why? 클래스의 constructor 메서드는 인스턴스를 반환해야 하지만 async함수는 언제나 프로미스를 반환해야 하기 때문입니다.

  • await 키워드

    • await 키워드는 프로미스가 settled 상태(비동기 처리가 수행된 상태)가 될때까지 대기하다가 settled 상태가 되면 프로미스가 resolve한 처리 결과를 반환합니다.

    • await 키워드는 반드시 프로미스 앞에서 사용해야 합니다.

    • async 함수 에러처리 방법

      • 첫째 : async함수 내에서 try, catch를 통해 에러를 해결합니다. 만약 async함수 내부에서 catch문을 사용해서 에러처리를 하지 않는다면 async함수는 발생한 에러를 reject하는 프로미스를 반환합니다.

      • 둘째 : 후속 처리 메서드 catch를 사용해서 async함수 외부에서 에러를 처리할 수도 있습니다.
profile
기본기가 탄탄한 개발자가 되자!

0개의 댓글