html,css,js

[자바스크립트 중급] Promise // then, catch, finally, Promise.all, Promise.race

코복이 2023. 5. 15. 16:32
728x90

0. 들어가며 : 비동기 처리

- 비동기 처리란 ‘특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 자바스크립트의 특성’

e.g) 값을 호출하는 중에 출력해버려서 값이 undefined로 나옴.

- 비동기 처리가 필요한 이유는 프론트에서 서버로 데이터를 요청했을 때 서버가 언제 그 요청에 답을 줄 지 모르는데 마냥 다른 코드들 멈춰놓고 기다릴수가 없기 때문. 하나씩 완료되고 처리 완료되고 처리 하면 아마 웹 애플리케이션을 실행하는데 수십 분은 걸릴 것.

- Promise는 비동기 처리를 위해 사용되는 객체

 

 

1. Promise 선언

- 지금은 없는데 나중에 완료되면 실행하고 오류나면 따로 알려줄게요~ 라고 '약속'

- 다른거 먼저 실행하세요 Promise는 완료되면 실행할게요.

// Promise
const promiseTest = new Promise((resolve, reject)=>{resolve()})

- resolve() : 성공한 경우, 반환

- reject() : 실패한 경우, 반환

 

- Promise 작업은 3가지 상태가 있음

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

 

 

2. Promise 실행 (then / catch / finally)

1) Promise 세팅 후

2) promise걸린변수명.then(function(){}).catch(function(){}).finally(function(){})

- then은 성공시 실행할 것

- catch는 실패시 실행할 것

- finally는 성공이든 실패든 마지막에 실행할 것

 

 

📌 성공만 세팅했을 때

// Promise
const proTest = new Promise((resolve, reject)=>{
    setTimeout(()=>{
        resolve('OK')
    }, 3000)
});

console.log(`시작`)

proTest.then(
    function(result){
        console.log(result)
    }
).catch(
function(err){
    console.log(err)
}
).finally(
    function(){
        console.log(`성공이던 실패던 실행완료시 출력`)
    }
)
 
---------- 실행 결과 --------------
시작
OK // 시작 나오고 3초뒤 출력
성공이던 실패던 실행완료시 출력 // OK와 함께 출력

 

 

📌 실패만 세팅했을 때

- 새로운 에러 띄우려면 new Error("에러 발생시 띄울 말") 이렇게 작성

// Promise
const proTest = new Promise((resolve, reject)=>{
    setTimeout(()=>{
        reject(new Error("err...."))
    }, 3000)
});

console.log(`시작`)

proTest.then(
    function(result){
        console.log(result)
    }
).catch(
function(err){
    console.log(err)
}
).finally(
    function(){
        console.log(`성공이던 실패던 실행완료시 출력`)
    }
)
---------- 실행 결과 --------------
시작
Error: err....
    at Timeout._onTimeout (c:\Users\user\Desktop\폴더\코딩연습\practice\main.js:4:16)
    at listOnTimeout (node:internal/timers:569:17)
    at process.processTimers (node:internal/timers:512:7)
성공이던 실패던 실행완료시 출력
 

 

 

📌 성공, 실패 함께 세팅하려면 : if 문 활용

// if 를 활용하여 resolve, reject 함께 조건 설정할 수 있다.
const arr = [1,2,3,4,5]

const getEgg = () => {
    return new Promise((resolve, reject) => {
        if (arr.length === 0) {
            reject("아무도 없다")
        } else
            (setTimeout(() => {
                resolve('egg')
            }, 1000))
    })
}

 

📌 연습

// Promise 연습
const test = function () {
    return new Promise((resolve, reject) => {
        resolve("성공")
    })
}

const test1 = function (something) {
    return new Promise((resolve, reject) => {
        resolve(`${something}했다`)
    })
}

const test2 = function (something2) {
    return new Promise((resolve, reject) => {
        resolve(`${something2}구요`)
    })
}

test()
    .then(test1)
    .then(test2)
    .then(console.log)
    .catch(error => new Error("err..."))
    .finally(() => console.log("만세"))
 
----------결과----------------
성공했다구요
만세

 

 

3. 콜백 함수 (callback) : 함수의 인수를 '함수'로 받는 것을 뜻 함.

- 콜백 함수를 이용하면 특정 로직이 끝났을 때 원하는 동작을 실행시킬 수 있음 (즉, 비동기 처리의 문제점을 해결)

const f1 = (callback1) => {
    setTimeout(() => {
        console.log("1번 완료")
        callback1(); // 여기서 인수로 받은 콜백함수를 1번완료 출력 이후에 실행하도록 함.
    }, 1000);
};

 

- 콜백 지옥 (Callback Hell) : 비동기 함수들의 중첩 실행 구조

1번완료하고 1번을 인수로 받아서 2번, 2번완료하고 2번을 인수로 받아서 3번 ... 뎁스가 깊어지며 계속해서 콜백함수를 불러오는 구조

// Callback Hell

// 1번완료 로그 찍고 인수로 받은 callback 함수를 실행해라
// f1(콜백함수); 실행하면 1번 완료 찍히고 콜백함수 실행
// f1의 인수로 f2를 하고 f2의 인수로 f3을 하고 ~~~ 쭉쭉 콜백헬

const f1 = (callback1) => {
    setTimeout(() => {
        console.log("1번 완료")
        callback1();
    }, 1000);
};

const f2 = (callback2) => {
    setTimeout(() => {
        console.log("2번 완료")
        callback2();
    }, 1000);
};

const f3 = (callback3) => {
    setTimeout(() => {
        console.log("3번 완료")
        callback3();
    }, 1000);
};

console.log("start")

f1(function () { // '1번 완료' 출력 후에 인수로 받은 함수(f2)를 실행 
    f2(function () { // '2번 완료' 출력 후에 인수로 받은 함수(f3)를 실행
        f3(function () { // '3번 완료' 출력 후에 인수로 받은 함수(console.log("end")를 실행
            console.log("end");
        });
    });
});

 

 

4. 프로미스 체이닝 Promises Chaining

- 콜백헬 대체 콜백헬처럼 프로미스가 연결연결 되는 것을 뜻함.

- then() 메소드는 Promise 객체를 '반환'해야 한다.

- return 을 잘 작성해주자.

// Promise 체이닝
const getEgg = () => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('egg')
      }, 1000)
    })
  };
 
  const getChicken = item => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(`${item} become Chicken`)
      }, 1000)
    })
  };
 
  const getBBQ = (item) => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(`${item} become BBQ CHICKEN`)
      }, 1000)
    })
  };
 
  getEgg()
    .then(겟에그결과값 => getChicken(겟에그결과값)) // 겟 에그 성공하면 ~ 결과값을 인수로 삼아 겟 치킨 함수 실행
    .then(겟치킨결과값 => getBBQ(겟치킨결과값))
    .then(겟비비큐결과값 => console.log(겟비비큐결과값))
    .catch(error => console.log(error))
 
// 3초 뒤
egg become Chicken become BBQ CHICKEN
 
// 아래처럼 생략할 수도 있음.
  getEgg()
    .then(getChicken)
    .then(getBBQ)
    .then(console.log)
    .catch(error => console.log(error))

 

5. Promises.all : 함수 병렬로 실행하고 모두 완료되면 한번에 출력

- 하나의 요소라도 누락되면 페이지를 보여주면 안되는 경우에 사용 (전부 완료됐을 때 보여주거나, 아예 안보여주거나)

- Promise.all() 메소드는 전달된 Promise 객체들이 모두 resolve될 때까지 기다린 후, 모든 Promise 객체의 결과값을 배열로 반환합니다.

- 배열을 인자로 받아 각각 병렬로 실행하고 완료되면 한번에 출력

- 그래서 Promise Chaining이 안됨 ★ 

- Promise.all([함수 배열]).then((완료되면 받는 인수)=>{그 인수 활용 완료되면 할 것})

 

// Promise.all

const getHen = () => {
    console.log("chicken완료")
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            resolve('chicken')
        },1000)
    })
}

const getEgg = item => {
    console.log("egg완료")
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            resolve(`${item} => egg`)
        },5000)
    })
}

const cook = item =>{
    console.log("요리 완료")
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            resolve(`${item} => friedegg`)
        },1000)
    })
};

Promise.all([getHen(), getEgg(), cook()]).then((item) => {
    console.log(item);
})
chicken완료 // 실행하자마자 출력
egg완료 // 실행하자마자 출력
요리 완료 // 실행하자마자 출력
[ 'chicken', 'undefined => egg', 'undefined => friedegg' ] // 함수 중 가장 처리속도가 늦은 5초 후에 출력 (체이닝 안됨)

 

 

6. Promises.race : 함수 병렬로 실행하고 모두 완료되면 한번에 출력

- 사용방법은 Promise.all과 동일 [배열로 함수를 받음]

- all 과 차이점은 all은 모든 작업이 끝날 때 까지 기다리지만, race는 '경주'이다. 하나라도 1등으로 완료된게 있으면 반환하고 끝냄.

- 중간에 reject 에러가 있어도 먼저된게 반환 (에러가 먼저되면 에러반환)

 

 

 

728x90