Promise

🙋🏻‍♀️·2022년 8월 15일
1

공부해보자고(이론)

목록 보기
12/14

Swag 넘치게 ㅅ ㅣ작~



✅Promise?

- 자바스크립트에서 제공하는 비동기를 간편하게 처리할 수 있는 object

  • 정상 수행: 성공메세지와 함께 처리된 결과값을 전달한다.(resolved)
  • 실패: 에러를 전달한다.(rejected)
  • 프라미스는 성공 또는 실패만 한다.
  • promise 이전에 비동기 통신을 할 때 사용되는 콜백함수의 단점을 보완하기 위해 promise 객체가 생겨나게 됨

😯callback 함수란?

특정 함수 내에서 어떤 이벤트가 발생했거나 특정 시점에 도달했을 때 시스템에서 호출하는 함수

  • 콜백 패턴을 사용하여 처리 순서를 보장하기 위해 중첩으로 인한 복잡도가 증가하였다.
    (비동기 통신 → 요청 → 응답 → 콜백 함수 수행 → 요청 → 응답 → 콜백함수 수행으로 발생하는 '무한 반복 콜백 현상'이 발생한다.)
  • 어떤 구문에서 에러가 발생하였을 때 에러 위치를 찾기가 어렵다.
  • 예외처리를 하는 데 있어서 어려움을 가지고 있다.


✔️무한 반복 콜백 현상

// 1초마다 숫자에 10을 더해준다.
const _number10Add = (num, callback) => {
    setTimeout(() => {
        callback(num + 10);
    }, 1000);
};

// 1초마다 숫자에 20을 더해준다.
const _number20Add = (num, callback) => {
    setTimeout(() => {
        callback(num + 20);
    }, 1000);
};

// 1초마다 숫자에 30을 더해준다.
const _number30Add = (num, callback) => {
    setTimeout(() => {
        callback(num + 30);
    }, 1000);
};

// 결과값을 콘솔에 출력한다.
const _numberLog = (number) =>
    new Promise(() => {
        setTimeout(() => console.log(number), 1000);
    });

// 최종 연산 값을 출력한다. => 반복 콜백 문제 발생
const resultConsole = () => {
    _number10Add(0, (callbackNum1) => {
        _number20Add(callbackNum1, (callbackNum2) => {
            _number30Add(callbackNum2, (callbackNum3) => {
                _numberLog(callbackNum3);
            });
        });
    });
};
resultConsole();

✔️Promise 함수로 변경한 예시

// 1초마다 숫자에 10을 더해준다.
const _number10Add = (num) => {
	return new Promise((resolve) => {
		setTimeout(() => {
			resolve(num + 10);
		}, 1000);
	});
};

// 1초마다 숫자에 20을 더해준다.
const _number20Add = (num) => {
	return new Promise((resolve) => {
		setTimeout(() => {
			resolve(num + 20);
		}, 1000);
	});
};

// 1초마다 숫자에 30을 더해준다.
const _number30Add = (num) => {
	return new Promise((resolve) => {
		setTimeout(() => {
			resolve(num + 30);
		}, 1000);
	});
};

// 결과값을 콘솔에 출력한다.
const _numberLog = (number) =>
	new Promise(() => {
		setTimeout(() => console.log(number), 1000);
	});

// 최종 연산 값을 출력한다.
const resultConsole = () => {
	_number10Add(0)
		.then((res) => _number20Add(res))
		.then((res) => _number30Add(res))
		.then((res) => _numberLog(res));
};



❗여기서 동기, 비동기의 차이란 무엇이냐면

  • 동기: 순서대로
  • 비동기: 순서X. 비동기적으로
    ~간단 설명 끝~



그런데 왜 ? ?ㅇㅙ,,wHy,, 비동기적인 처리가 필요할까???

ex) youtube 켬-> 데이터 불러오는 약 2초동안 화면에 아무것도 안뜸->사용자 입장에선 불편함😑..

=> 비동기적인 처리가 필요함







✔️new Promise(executor) ->(promise의 형태)


- Promise를 생성하게되면 executor(실행함수)가 바로 실행된다.

  • executor
    resolve 및 reject 인수를 전달할 실행 함수. 실행 함수는 프로미스 구현에 의해 resolve와 reject 함수를 받아 즉시 실행됩니다(실행 함수는 Promise 생성자가 생성한 객체를 반환하기도 전에 호출됩니다). resolve 및 reject 함수는 호출할 때 각각 프로미스를 이행하거나 거부합니다. 실행 함수는 보통 어떤 비동기 작업을 시작한 후 모든 작업을 끝내면 resolve를 호출해 프로미스를 이행하고, 오류가 발생한 경우 reject를 호출해 거부합니다. 실행 함수에서 오류를 던지면 프로미스는 거부됩니다. 실행 함수의 반환값은 무시됩니다.

- Promise는 클래스 문법과 같이 new 키워드와 생성자를 사용해 만든다.

  • Promise 객체는 new 키워드와 생성자를 사용해 만듭니다. 생성자는 매개변수로 "실행 함수"를 받습니다. 이 함수는 매개 변수로 두 가지 함수를 받아야 하는데, 첫 번째 함수(resolve)는 비동기 작업을 성공적으로 완료해 결과를 값으로 반환할 때 호출해야 하고, 두 번째 함수(reject)는 작업이 실패하여 오류의 원인을 반환할 때 호출하면 됩니다. 두 번째 함수는 주로 오류 객체를 받습니다.
const myFirstPromise = new Promise((resolve, reject) => {
  // do something asynchronous which eventually calls either:
  //	(=둘 중 하나를 부르는 비동기적인 일을 한다)
  //   resolve(someValue)        // fulfilled(성공)
  // or
  //   reject("failure reason")  // rejected(실패)
});

- Promise를 즉시 실행할 수도 있고 then으로 호출하여 필요시에 사용할 수도 있다.


📖 Example(출처-https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise)

function myAsyncFunction(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open("GET", url)
    xhr.onload = () => resolve(xhr.responseText)
    xhr.onerror = () => reject(xhr.statusText)
    xhr.send()
  });
}






✅Promise에서 가장 중요한 state ⭐⭐⭐

  1. pending(대기): 초기 상태
  2. Fulfilled(이행): 성공적으로 완료된 상태
  3. Rejected(실패): 실패 상태





- 5초 뒤 안녕찍히면서 상태 변함


✅Promise를 소비(사용)하는 .then .catch finally

promise
	.then((result)=>{  
  console.log(result) // 성공(정상작동일때 then메소드에서 값을 처리)
})
	.catch((error)=>{
  console.log(error) // 실패(오류를 잡음)
})
	.finally(()=>{
  console.log('성공이든 실패든 실행된다')
})




✍🏻코드로 Promise 이해해보기

const getApple = () => 
  new Promise((resolve,reject)=>{
    setTimeout(()=> resolve('🍎'), 1000)
  })

const getBanana = (apple) =>
	new Promise((resolve,reject)=>{
    setTimeout(()=>resolve(`${apple} => 🍌`), 1000)
  })

const getTrain = (banana) =>
	new Promise((resolve,reject)=> {
  	setTimeout(()=> resolve(`${banana} => 🚈`), 1000)
  })

// getApple()
// 	.then((banana)=> getBanana(banana))
// 	.then((train)=> getTrain(train))
// 	.then((result)=> console.log(result))

getApple()
	.then(getBanana)
	.then(getTrain)
	.then(console.log)
//'🍎 => 🍌 => 🚈'

✔️ getApple() 위쪽은 Promise를 제공하는 곳! .then()부분은 Promise를 소비하는 곳!



✍catch 사용해서 에러 잡는법

const getApple = () => 
  new Promise((resolve,reject)=>{
    setTimeout(()=> resolve('🍎'), 1000)
  })

const getBanana = (apple) =>
	new Promise((resolve,reject)=>{
    setTimeout(()=>reject(new Error (`${apple} => 🍌`)), 1000)
  })						//getBanana 함수에서 Error를 입력함

const getTrain = (banana) =>
	new Promise((resolve,reject)=> {
  	setTimeout(()=> resolve(`${banana} => 🚈`), 1000)
  })

getApple()
	.then(getBanana)
	.catch((error)=> {
  return '🍍'
}) 							//return 값으로 파인애플을 입력함
	.then(getTrain)
	.then(console.log)
//"🍍 => 🚈" (사과와 바나나는 없어지고 파인애플과 기차만 남음)


✅Promise.all과 Promise.race

  • all은 제일 늦게 끝나는 것 기준
  • race는 제일 빨리 끝나는 것 기준

✔️Promise.all

function timer(time) {
  return new Promise((resolve,reject)=> {
    setTimeout(()=>{
      resolve(time)
    },time)
  })
} //비동기 로직으로 성공적으로 완료되어 time의 숫자를 결과값으로 반환한다.

console.time('all')
Promise.all([timer(1000), timer(2000), timer(3000)]).then((result)=> {
  console.log('result', result)
  console.timeEnd('all')
})
//'result' [ 1000, 2000, 3000 ]
//'all: 3001ms'



✍🏻Promise.all 특징

  • 순서대로 실행되지만, 앞의 함수를 기다리지 않는다.
  • 무조건 비동기 방식에서만 사용한다.
    (그래서 비동기식으로 사용하지 않으면 그 데이터는 불러오지 못했기 때문에 pending상태로 불려짐)
  • 하나라도 reject에 해당된다면 결과값은 reject값이 된다.
    (ex. 하나라도 누락되면 페이지 안보여줄때 사용함)
  • 모든 promise를 실행한 후 진행되는 하나의 promise를 반환함✔️




✔️Promise.race

function timer(time) {
  return new Promise((resolve,reject)=> {
    setTimeout(()=>{
      resolve(time)
    },time)
  })
} //비동기 로직으로 성공적으로 완료되어 time의 숫자를 결과값으로 반환한다.

console.time('all')
Promise.race([timer(1000), timer(2000), timer(3000)]).then((result)=> {
  console.log('result', result)
  console.timeEnd('all')
})
//'result' 1000
//'all: 1009ms'



❗정리

  • 동시에 트리거가 된다(약간의 차이 있음)
  • promise.all: 마지막 기준
  • promise.race: 처음 기준

0개의 댓글