반응형
Notice
Recent Posts
Recent Comments
Link
«   2025/09   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Archives
Today
Total
관리 메뉴

웹풀스택 공부 중

10 - 3. Callback & Promise 본문

카테고리 없음

10 - 3. Callback & Promise

lukeit 2024. 10. 10. 17:41

개인적으로 제일 어려워하는 부분이지만 화이팅해보자.

Callback

Callback ≠ Asynchronous

  • 함수 (= Callback)을 파라미터로 넘겨 (일급 함수), 파라미터를 받은 함수에게 실행권을 넘기는 함수
    • “함수를 Parameter로 넘길때, 실행권한도 같이 넘기는 함수이다”
function callback(param1, param2){
    console.log(param1 + and + param2)
}

function caller(callback){
    callback(arguments[1], arguments[2]);
}

caller(callback, "hello", "goodbye");
  • arguments[n] 를 사용해 넘겨줄 수 있다
  • 비동기적인 개념이 아니다
    • 비동기적 기능을 가지진 않았지만 비동기에 필수적인 존재이다
      • “비동기 로직이 끝나거든 그 비동기 로직의 결과값을 통해 Callback을 실행해주세요”
  • 비동기의 꽃이긴하다…
    • 비동기 함수에게 실행권을 넘기기 위해 Callback을 많이 사용할뿐

Callback Hell

  • Callback 결과값이 순차적으로 필요할때 발생한다
    • 결과값이 서로 의존되어있다고 보면 된다
    • “Callback의 결과가 그 다음 Callback 실행에도 필요한 경우”

Promise

Promise is an object that may produce a signle value some time in the future

  • Promise = Callback + Asynch

    • Asynch (비동기 함수) Caller (= Executor): Producer - 파라미터를 주입한다
    • Callback (비동기 처리후 실행할 함수) Callee (= Executee) = Consumer - 파라미터를 받아 수행한다
      • Executor에게 자신의 제어권을 넘긴다
      • Consumer가 없을 때 Pending Promise가 반환된다
  • 모든 Promise는

    • 결과를 비동기로 생성하고 끝날때 callback을 호출한다

      • 두가지 callback을 호출할 수 있다: sucess , fail
    • 가질 수 있는 상태

      • Pending (대기): 결과를 기다리는 중 (비동기 처리 로직이 아직 완료되지 않은 상태)

        • 먼저 new Promise() 메서드를 호출하면 대기 (Pending) 상태가 된다
        • new Promise(function(resolve,reject)){ ... } 처럼 콜백 함수(=function)을 선언할 수 있고, Parameter를 resolvereject 로 줄 수 있다
      • Fulfiled (이행): 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태

        • 위 상태에서 new Promise(...) { resolve() } 를 실행하면 이행 (Fulfiled)상태가 된다

        • 이행상태가 된다면 then(...) 을 통해 처리 결과 값을 받을 수 있다

          function getData() {
          return new Promise(function(resolve, reject) {
            var data = 100;
            resolve(data);
          });
          }
          
          // resolve()의 결과 값 data를 resolvedData로 받음
          getData().then(function(resolvedData) {
          console.log(resolvedData); // 100
          });
      • Rejected (실패): 비동기 처리가 실패하거나 오류가 발생한 상태

        • 위 상태에서 new Promise(...) { reject() } 를 호출 시 실패 (Reject)상태가 된다

        • 실패 상태가 되면 실패한 이유 (실패 처리의 결과 값)을 .catch() 로 받을 수 있다

          function getData() {
          return new Promise(function(resolve, reject) {
            reject(new Error("Request is failed"));
          });
          }
          
          // reject()의 결과 값 Error를 err에 받음
          getData().then().catch(function(err) {
          console.log(err); // Error: Request is failed
          });
  • 주로 서버에서 받아온 데이터를 화면에 표시할때 사용한다

    • 데이터를 달라고 서버에 요청을 보냈으나 받아오기도 전에 데이터를 받아온 것 처럼 화면에 데이터를 표시하려고 할 시 오류가 발생하는것을 방지하기 위함
  • 실제 사용예시

    new Promise((resolve, reject) => {
        const result = getUserInformationAPI()
        if (result.success) { resolve(result.user) }
        if (result.failed) { reject({ type: 'No User', message: 'Error Occured' }) }
    })
        .then((user) => { console.log(user) })
        .catch((error) => { console.log(error.message) })
  • 즉, .then 을 사용해 성공한 결과값을 받고, .catch() 를 사용해 실패한 결과값을 받을 수 있다

    • .finally 를 사용한다면 성공하든 실패하든 실행할 callback함수를 설정해줄 수 있다

    • 이것들을 사용하여 Chaining이 가능해진다

      • ex.) .then 으로 반환되는 값에 또 .then 을 붙일 수 잇따!

      • ex.)

        step1(value1)
              .then((value2) => {
                      return step2(value2)
              })
              .then((value3) => {
                      return step3(value3)
              })
              .then((value4) => {
                      console.log(value4)
              })
      • 이 방법을 통해 Promise Hell을 해결할 수 있다

        • Promise Hell: 결과 값을 순차적으로 연결할 때 발생한다
          • Promise의 결과가 그 다음 Promise 실행에 필요한 경우
        step1(value1)
              .then((value2) => {
                      step2(value2)
                              .then((value3) => {
                                      step3(value3)
                                              .then((value4) => {
                                                      console.log(value4)
                                              })
                              })
              })

Async / Await

  • Promise Hell 해결 방법 2 이다

    • Async와 Await으로 변환하여 모든 값을 사용할 수 있다

    • 성공 / 실패에 따른 Callback이 존재하지 않기 때문에

      • 성공했을때 그대로 값을 쓰면 되지만
      • 실패했을때는 Exception처리가 필요하다
        • try-catch 를 사용하면 된다
    • 위의 Promise Hell을 await으로 변환한 예제

      const value2 = await step1(value1)
      const value3 = await step2(value2)
      const value4 = await step3(value3)
      console.log(value4)

더 쉽게 이해해보기

  • async = Promise 라는 “상자”를 반환한다
    • Promise.resolve로 감싸져있으면 바로 반환, 아니면 상자 포장 반환
  • await = Promise 라는 “상자”를 연다
    • Promise 객체가 오기까지 기다렸다가 상자를 열어 내부의 값을 반환한다

  • async 가 붙은 함수는 반드시 Promise를 반환하고, Promise가 아니더라도 Promise로 감싸 반환한다
async function returnpromise() {
  return Promise.resolve(1)
}
returnpromise()                   // Promise { <fulfilled>, 1 }
await returnpromise()             // 1
returnpromise().then(console.log) // 1

// 1이 Promise가 아니여도 Promise로 감쌌다!
async function returnpromise() {
  return 1
}
returnpromise()                   // Promise { <fulfilled>, 1 }
await returnpromise()             // 1
returnpromise().then(console.log) // 1
  • await 키워드를 만다면 Promise가 처리될 때까지 기다린다
async function returningPromise() {
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => resolve('완료!'), 1000)
    })

    let result = await promise   // 위의 Promise가 이행될 때 까지 기다린다
    console.log(result)
}

returningPromise()

// 아래의 경우에는 await을 사용하지 않아 바로 Promise가 나와버렸다.

async function returningpromise() {
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve('완료!'), 1000)
  });

  let result = promise // 프라미스를 기다리지않고, 프라미스 객체 그대로 반환
  console.log(result)  // Promise { <pending> }
}

returningpromise()
반응형