동기&비동기(4) - Promise

조뮁·2022년 9월 3일
0

React-이론

목록 보기
10/12

비동기 함수의 결과를 또 다른 비동기함수의 인자로 사용하는 방법

  • callback Hell
function taskA(a, b, cb){
  setTimeout(() => {
    const res = a + b;
    cb(res);
  }, 3000);
}

function taskB(a, cb){
  setTimeout(()=>{
    const res = a * 2;
    cb(res);
  }, 1000)
}

// 인수값에 -1 한 값을 출력하는 함수
function taskC(a, cb){
  setTimeout(()=>{
    const res = a-1;
    cb(res)
  }, 2000)
}

// 콜백함수의 결과값을 활용하기 위해 콜백 함수 안에 또 다른 콜백함수가 파고들게 작성됨
taskA(1, 2, (a_res)=>{
  console.log(`A RESULT : ${a_res}`);
  // taskA의 결과값을 taskB의 인자로 전달
  taskB(a_res, (b_res)=>{
    console.log(`B RESULT : ${b_res}`);
    // taskB의 결과값을 taskC의 인자로 전달
    taskC(b_res, (c_res)=>{
      console.log(`C RESULT : ${c_res}`);
    })
  })
})

console.log('코드 끝');

promise

: 자바스크립트 비동기 처리에 사용되는 객체

비동기 작업의 상태값

  1. pending (대기 상태)
    : 비동기 작업이 진행중이거나, 시작할 수 없는 문제가 발생
  2. fulfilled (성공)
    : 비동기 작업이 정상 완료된 상태
    : resolve 과정을 거쳐 fulfilled 상태가 됨
    : pending -> resolve(해결) -> fulfilled
  3. rejected (실패)
    : 비동기 작업이 실패함
    : 서버 무응답, 작업 시간 초과로 인한 실패 등
    : reject 과정을 거쳐 rejected 상태가 됨
    : pending -> reject(거부) -> rejected

  • 비동기 작업은 한 번 성공/실패 시 작업이 종료됨.

Promise 기본 사용법

https://elvanov.com/2597

const promise1 = new Promise((resolve, reject) => {
  // 비동기 작업
});
  • const로 Promise 객체를 생성하는 것이 가독성과 유지보수성 높일 수 있음
  • new Promise(func) 로 Promise 객체 생성. 생성자는 함수이기 때문에 ()를 사용하여 함수를 호출하듯이 사용
  • 생성자는 함수를 인자로 받음
    • 인자로 받는 함수 : executor

executor

  • 첫 번째 인수로 resolve, 두 번째 인수로 reject를 받음 (인수 이름은 우리가 정해도 되지만, 이게국룰임)
  • resolve와 reject는 executor 내에서 실행할 수 있는 또 다른 함수.

  • 2초 뒤 전달받은 값의 양/음수 여부를 판단하는 함수
function isPositive(num, cbres, cbrej){  // 결과값은 callback 함수를 이용해서 받음. resolve, reject는 callback 함수임
  setTimeout(()=>{
    // 파라미터가 number타입인지 확인
    if(typeof num === 'number'){
      // 비동기 작업 성공 (resolve)
      cbres(num >= 0 ? '양수' : '음수');
    }else{
      // 비동기 작업 실패 (reject)
      cbrej('주어진 값이 숫자형 값이 아닙니다.');
    }
  }, 2000)
}

// resolve 와 reject는 isPositive를 호출하면서 생성해줘야함
isPositive('문자', (res)=>{
  console.log(`성공적으로 수행됨 : ${res}`);
}, (err)=>{
  console.log(`실패함 : ${err}`);
});
// "성공적으로 수행됨 : 양수"
// "성공적으로 수행됨 : 음수"
// "실패함 : 주어진 값이 숫자형 값이 아닙니다."
  • promise 이용
// 2초 뒤 전달받은 값의 양/음수 여부를 판단하는 함수
function isPositiveP(num){  // num 파라미터를 isPositive()와 똑같이 받음
  const executor = (cbres, cbrej) => {  // executor : 실행자 -> 비동기함수를 실질적으로 수행하는 함수
    setTimeout(()=>{
      // 파라미터가 number타입인지 확인
      if(typeof num === 'number'){
        // 비동기 작업 성공 (resolve)
        console.log(num);
        cbres(num >= 0 ? '양수' : '음수');
      }else{
        // 비동기 작업 실패 (reject)
        cbrej('주어진 값이 숫자형 값이 아닙니다.');
      }
    }, 2000)
  }
  
  // 비동기 작업 자체인 promise를 저장할 상수 asyncTask를 만든 후, new키워드를 사용해 프로미스 객체를 생성하면서, 프로미스 객체의 생성자로 비동기함수의 실질적인 실행자함수(executor)를 넘겨주면, 자동으로 executor함수가 바로 수행됨.
  const asyncTask = new Promise(executor);
  // executor를 담은 프로미스 객체를 asycTask라는 객체에 담았으니까, 이 상수를 바로 리턴해주면 isPositiveP의 반환값이 프로미스로 바뀜
  // 어떤 함수가 promise를 반환한다는 것 = 이 함수는 비동기작업을 하고 그 결과를 프로미스 객체로 반환받아서 사용할 수 있는 함수임
  return asyncTask;
}

// isPositiveP가 반환하는 프로미스 객체를 res라는 상수에 저장
const res = isPositiveP(1);
// res라는 상수가 반환받은 promise객체를 이용해서, 비동기처리에 대한 res, rej의 결과값을 자유롭게 사용할 수 있음

// 프로미스 객체의 비동기처리 결과 사용법
res.then((res)=>{
  console.log(`작업 성공 : ${res}`);
}).catch((err)=>{
  console.log(`작업 실패 : ${err}`);
})

// 결과값 = 작업성공 : 양수
// resolve에서 전달한 '양수'라는 값이 res.then 안의 callback 함수에 들어와서 실행됨

// promise 객체의 메서드인 then을 사용하면 resolve 수행 시 결과값을 콜백함수에서 받아 사용할 수 있음
// reject수행 결과는 .catch 메서드에서 사용할 수 있음

  • 문자형 전달 시
// 2초 뒤 전달받은 값의 양/음수 여부를 판단하는 함수
function isPositiveP(num){  // num 파라미터를 isPositive()와 똑같이 받음
  const executor = (cbres, cbrej) => {  // executor : 실행자 -> 비동기함수를 실질적으로 수행하는 함수
    setTimeout(()=>{
      // 파라미터가 number타입인지 확인
      if(typeof num === 'number'){
        // 비동기 작업 성공 (resolve)
        console.log(num);
        cbres(num >= 0 ? '양수' : '음수');
      }else{
        // 비동기 작업 실패 (reject)
        cbrej('주어진 값이 숫자형 값이 아닙니다.');
      }
    }, 2000)
  }
  
  // isPositiveP()함수에서 executor 비동기 작업을 실행시키는 방법
  // 비동기 작업 자체인 promise를 저장할 상수 asyncTask를 만든 후, new키워드를 사용해 프로미스 객체를 생성하면서, 프로미스 객체의 생성자로 비동기함수의 실질적인 실행자함수(executor)를 넘겨주면, 자동으로 executor함수가 바로 수행됨.
  const asyncTask = new Promise(executor);
  // executor를 담은 프로미스 객체를 asycTask라는 객체에 담았으니까, 이 상수를 바로 리턴해주면 isPositiveP의 반환값이 프로미스로 바뀜
  // 어떤 함수가 promise를 반환한다는 것 = 이 함수는 비동기작업을 하고 그 결과를 프로미스 객체로 반환받아서 사용할 수 있는 함수임
  return asyncTask;
}

// isPositiveP가 반환하는 프로미스 객체를 res라는 상수에 저장
const res = isPositiveP('문자');
// res라는 상수가 반환받은 promise객체를 이용해서, 비동기처리에 대한 res, rej의 결과값을 자유롭게 사용할 수 있음

// 프로미스 객체의 비동기처리 결과 사용법
res.then((res)=>{
  console.log(`작업 성공 : ${res}`);
}).catch((err)=>{
  console.log(`작업 실패 : ${err}`);
})

// 결과 = "작업 실패 : 주어진 값이 숫자형 값이 아닙니다."


then chaining

  • callback hell -> Promise 이용하여 변경
function taskA(a, b) {
  // new Promise()에 resolve, reject 콜백함수가 있기 때문에 cb는 필요 없음
  // 함수가 Promise 객체를 반환함 === 함수가 비동기적으로 동작하고, 반환한 프로미스 객체를 이용해서 비동기처리의 결과값을 then, catch로 이용할 수 있게 할 것임
  const promiseA = new Promise((resolve, reject) => {
    setTimeout(() => {
      const res = a + b;
      resolve(res);
    }, 3000);
  });
  return promiseA;
}

function taskB(a) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const res = a * 2;
      resolve(res);
    }, 1000);
  });
}

function taskC(a) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const res = a * -1;
      resolve(res);
    }, 2000);
  });
}

// taskA(5, 1) 자체로 Promise 객체를 반환받음
/* callback hell 방식
taskA(5, 1).then((a_res) => {
  console.log(`A 결과 : ${a_res}`);
  taskB(a_res).then((b_res) => {
    console.log(`B 결과값 : ${b_res}`);
    taskC(b_res).then((c_res) => {
      console.log(`C 결과값 : ${c_res}`);
    });
  });
});
*/

// then chaining
taskA(5, 1)
  .then((a_res) => {
    console.log(`A 결과값 : ${a_res}`);
    return taskB(a_res); // taskA의 then 콜백함수가 수행되면서 taskB()의 결과값을 return함.
  })
  .then((b_res) => {
    // taskB()의 결과값을 b_res로 받아서 콜백함수 수행
    console.log(`B 결과값 : ${b_res}`);
    return taskC(b_res); // taskC()의 결과값을 return함
  })
  .then((c_res) => {
    // tackC()의 Promise를 받아서 then 콜백함수 수행
    console.log(`C 결과값 : ${c_res}`);
  });
  • 비동기 작업의 분리 및 다른 작업 추가 가능
  • 비동기 처리 호출 코드와 결과 처리 코드 분리 가능

// taskA()는 taskB(a_res)를 반환하기 때문에, taskB의 프로미스임.
// 즉, taskA() 자체를 B Promise로 생각해서 변수에 받아 사용 가능
const bPromiseRes = taskA(5, 1).then((a_res) => {
  console.log(`A 결과값 : ${a_res}`);
  return taskB(a_res);
});

// Promise 작업 사이에 자유롭게 다른 작업을 추가할 수 있음
console.log("a작업 완료~ b작업 시작예정~");

const cPromiseRes = bPromiseRes.then((b_res) => {
  console.log(`B 결과값 : ${b_res}`);
  return taskC(b_res);
});
cPromiseRes.then((c_res) => {
  console.log(`C 결과값 : ${c_res}`);
});

0개의 댓글