[JavaScript] Promise

Narcoker·2022년 8월 29일
0

JavaScript

목록 보기
18/55

Promise

프로미스는 자바스크립트 비동기 처리에 사용되는 객체이다. 여기서 자바스크립트의 비동기 처리란 ‘특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 자바스크립트의 특성’을 의미합니다
사용법은 다음과 같다.

const pr = new Promise((resolve, reject) => {
  //code
});

callback 함수

resolve는 성공했을때 실행하는 함수이고, reject는 실패했을 때 실행되는 함수이다. 이런식으로 어떤 작업이 끝났을때 실행되는 함수를 callback 함수라고한다.

Promise 동작 방식

new Promise가 생성하는 Property는 state와 result가 있다.

초기

  • state: pending(대기)
  • result: undefined

resolve(value) 호출시, 성공

  • state: fulfilled(이행됨)
  • result: value

reject(error) 호출시, 실패

  • state: rejected(거부됨)
  • result: error


3초 뒤 resolve('OK')가 실행되고 Promise의 Property는 위와 같이 변경된다.


3초 뒤 rejected가 실행되고 Promise의 Property는 위와 같이 변경된다.


.then()을 이용해서 성공과 실패시 실행되는 함수를 작성할 수 있다.
첫번째 함수는 성공시 실행되는 함수, 두번째 함수는 실패시 실행되는 함수이다.
위 코드는 3초뒤 성공하기 때문에 두번째 함수는 실행되지 않는다.

다른 방식으로 작성할 수 있는데 이처럼 코드를 작성하면 가독성이 올라간다.
또한 성공 함수 수행도중 나오는 에러도 잡을 수 있다.


catch와 함께 사용할 수 있는 구문인 finally이다. then이든 catch든 모든 함수가 수행되고 반드시 실행되는 구문을 만들 수 있다.

예제

1초 뒤 Promise state를 fulfilled로 변경하고 OK를 반환값으로 넣어준다.(result) 이후 then이 실행되어 OK를 출력하고 finally구문의 console.log("끝") 을 실행한다.

const pr = new Promise((resolve, reject) => {
  setTimeout(()=>{
    resolve("OK");
    // reject(new Error("error"));
  }, 1000);
});
console.log('시작');
pr.then((result) => {
  console.log(result));
})
.catch((err) =>{
  console.log(err);
})
.finally(()=>{
  console.log('끝');
});

callback hell

'시작'이 출력되고
fn1 실행
1초 뒤에 '1번 주문 완료' -> fn2
3초 뒤에 '2번 주문 완료' -> fn3
2초 뒤에 '3번 주문 완료' -> console.log('끝')
이런식으로 depth가 깊어지면서 계속 콜백함수를 호출하는 것을
callback hell 이라한다.

const f1 = (callback) => {
  setTimeout(function() {
    console.log('1번 주문 완료');
    callback();
  }, 1000);
};
const f2 = (callback) => {
  setTimeout(function() {
    console.log('2번 주문 완료');
    callback();
  }, 3000);
};
const f3 = (callback) => {
  setTimeout(function() {
    console.log('3번 주문 완료');
    callback();
  }, 2000);
};
console.log('시작');
f1(function(){
  f2(function(){
    f3(function(){
      console.log('끝');
    });
  });
});

Promise Chaining

다음과 같이 Promise가 연결된 것을 Promise Chaining 이라한다.

return 값을 Promise 값으로하지 않아도 Promise 객체로 반환된다.
return 3; 을 하게 되면 Promise 객체의 value는 3이된다.

이러한 메커니즘으로 인해 Promise Chaining이 가능한 것이다.

만약 중간 Promise 에서 실패할 경우 다음 Promise는 실행되지않고
Finally 구문으로 간다.

const f1 = () => {
    return new Promise((res, rej) => {
        setTimeout(() => {
            res('1번 주문 완료');
        }, 1000);
    });
};
const f2 = (message) => {
    return new Promise((res, rej) => {
        console.log(message); // '1번 주문 완료'
        setTimeout(() => {
            res('2번 주문 완료');
        }, 3000);
    });
};
const f3 = (message) => {
    return new Promise((res, rej) => {
        console.log(message); // '2번 주문 완료'
        setTimeout(() => {
            res('3번 주문 완료');
        }, 2000);
    });
};
console.log('시작');
f1()
    .then(res => f2(res)) // res = '1번 주문 완료'
    .then(res => f3(res)) // res = '2번 주문 완료'
    .then(res => console.log(res)) // res = '3번 주문 완료'
    .catch(console.log)
    .finally(() => {
        console.log("끝");
    });

Promise.resolve()

성공(fulfilled) 상태의 Promise 인스턴스를 생성하여 반환한다.
Promise.resolve() 형태로 작성한다.
파라미터 값에 따라 생성 방법이 다른다.

파라미터에 값을 작성하면 파라미터 값으로 Promise 인스턴스를 생성하여 반환한다.

파라미터네 Promise 인스턴스를 작성하면
파라미터의 Promise 인스턴스의 값을 사용하여 Promise 인스턴스를 생성하여 반환한다.

const obj = Promise.resolve( ["sports", "music"] );

Promise.resolve(obj).then((param) => { console.log( param ) }); // [sport, music]

Promise.thenable

Promise.resolve() 의 파라미터에 then() 을 작성한 형태

const obj. = Promise.resolve({
	then(resolve, reject){
    	resolve([1,2]);
    }
});
obj.then((value) => { log(value) } );
console.log("끝");
/*
끝
[1,2]
*/

Promise.reject()

실패(reject) 상태의 Promise 인스턴스를 생성하여 반환한다.
파라미터로는 reject의 실패 사유를 작성한다.

const obj = Promise.reject("실패");
obj.then(
	(value) => console.log(value),
    (value) => console.log(value); // 실행
);
// 실패
const obj = new Error("에러 발생")
Promise.reject(obj).catch(
	(error) => console.log(error.message);
);
console.log("끝");
/*
끝
에러 발생
*/

Promise.all()

Promise 들을 동시에 실행시키고자 하는 경우 Promise들을 배열안에 넣어 매개변수로 넣어준다.
모든 함수가 성공해야 값을 사용할 수 있다. => 모든 함수가 실행되어야 then 이 실행된다.

console.time('x');
Promise.all([f1(), f2(), f3()]).then(
res=>{ 
	console.log(res); // [ '1번 주문 완료', '2번 주문 완료', '3번 주문 완료' ]
    console.timeEnd('x'); // 3.004s
});

중간에 실패하는 경우 Promise.resolve는 실행되지 않는다.
단, 주어진 모든 함수가 수행되긴한다.
브라우저가 데이터를 다 가지고오지 못할때 페이지를 누락해야하는 경우 유용하다.

function order(delay) {
	return new Promise((resolve, rejecjt => {
    	setTimeout(()=>{
        	console.log(delay);
            delay === 300 ? reject(delay) : resolve(delay);
       	}, delay);
    });
};
Promise.all([order(500), order(100), order(300)])
	   .then((param => console.log(성공:" + param),
       	     (param => console.log(실패:" + param));
/*
100
300
실패: 300
500
*/             

Promise.race()

하나라도 작업이 끝나면 그 이상 수행하지 않는다.

function order(delay) {
	return new Promise((resolve, rejecjt => {
    	setTimeout(()=>{
        	console.log(delay);
            resolve(delay);
       	}, delay);
    });
};
Promise.all([order(500), order(100), order(300)])
	   .then((param => console.log("then:" + param));
/*
100
then: 100
300
500
*/

Promise.any()

race()는 모든 Promise를 보는 반면
any()는 성공하는 작업들중 가장 빠른 Promise를 반환한다.
만약 모두 거부시 에러를 발생시킨다.

const rejPromise = new Promise((res, rej) => {
  setTimeout(()=>{
    rej("fail..");
  ),1000);
});
const resPromise = new Promise((res, rej) => {
  setTimeout(()=>{
    res("success");
  },2000);
});
Promise.race([rejPromise, resPromise]);
  .then(()=> console.log("성공"))
  .catch(e => console.log(e)); // fail 
Promise.any([rejPromise, resPromise]);
  .then(()=> console.log("성공"))
  .catch(e => console.log(e)); // 성공
profile
열정, 끈기, 집념의 Frontend Developer

0개의 댓글