상세 컨텐츠

본문 제목

코드카데미 Javascript - 프로미스와 비동기 처리

IT/Javascript

by J KIMS 2020. 10. 7. 08:49

본문

반응형

 

프로미스

 

asynchronous operation (비동기 처리)은 다른 작업이 완수되는 동안 다른 일로 넘어가는 것

예를 들면 network requestquerying a database 같이 시간이 걸리는 작업들을 기다리지 않고 다음 코드를 실행하는 것이다.

 

Promise비동기 처리의 결과를 나타내는 객체

프로미스의 상태에는 다음 세가지가 존재할 수 있음

  • 대기 Pending : 초기 상태 - 비동기 처리가 아직 안 끝남

  • 이행 Fulfilled : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태

  • 거부 Rejected : 비동기 처리가 실패한 상태

프로미스가 더 이상 대기 상태가 아니라면 확정(settled)되었다고 한다.

그 상태는 이행(Fulfilled)이거나 거부(Rejected) 둘 중 하나임.

 


프로미스 객체를 만드는 법

 

const executorFunction = (resolve, reject) => { };
const myFirstPromise = new Promise(executorFunction);

 

Promise의 생성자(constructor)executor function을 파라미터로 가진다.

 

executor function은 비동기 처리를 시작하고 프로미스가 어떻게 확정되어야 하는지 나타낸다.

그리고 resolve()reject() 함수 두 가지를 가진다. 이것들은 프로그래머가 정의하는 것이 아니라 자바스크립트가 고유의 함수를 파라미터로 전달한다.

 

  • resolve : 인자 하나를 가지는 함수. resolve가 호출되면 프로미스의 상태를 pending에서 fulfilled로 바꿈. 프로미스의 resolved value는 resolve에 인자로 전달된 값으로 확정됨.

  • reject :  reason이나 error를 인자로 가지는 함수. 호출되면 프로미스의 상태는 pending에서 rejected로 바꿈. 그리고 전달받은 인자를 rejection reason으로 설정함.


setTimeout()

 

setTimeout()은 Node API이다. 어떤 작업을 일정 시간이 지난 후 실행하게 만든다.

콜백함수딜레이 되는 시간(밀리초)을 파라미터로 가진다.

 

const delayedHello = () => {
  console.log('Hi! This is an asynchronous greeting!');
};

setTimeout(delayedHello, 2000);

 

이렇게 코드를 작성하면 적어도 2초 후에 콜백함수가 호출된다.

 

적어도라고 한 이유는 자바스크립트가 비동기 처리를 할 때는 바로 실행가능한 다른 코드를 먼처 실행하기 때문이다. 만약에 본문에 다른 코드가 포함되어있다면 그 코드를 먼저 실행하고 delayedHello 함수를 호출하느라 2초 이상 걸릴 수도 있다. (이런 걸 이벤트 루프라고 하는 듯)

 

~비동기적 프로미스를 만드는 법~

 

const returnPromiseFunction = () => {
  return new Promise((resolve, reject) => {
    setTimeout(( ) => {resolve('I resolved!')}, 1000);
  });
};

const prom = returnPromiseFunction();

 

연습으로 작성한 코드

 

console.log("This is the first line of code in app.js.");

const usingSTO = () => console.log('Yay! Coding is so fun!!');
setTimeout(usingSTO, 2000);

console.log("This is the last line of code in app.js.");

 

출력 결과 (usingSTO함수가 늦게 호출됨)

 


.then()

  • 프로미스 객체의 상태가 결정되면 그 다음으로 해야할 일을 결정하는 함수

  • higher-order-function 이다

  • 두 개의 콜백 함수를 인자로 가짐

  • 이 콜백함수들을 핸들러(handler)라고 함

  • 프로미스의 상태에 따라 적절한 핸들러가 호출됨

  • 성공시 호출되는 핸들러를 onFulfilled 실패시 호출되는 핸들러를 onRejected라고 하기도함

  • 한 가지 중요한 .then()의 특징은 항상 프로미스를 리턴한다는 것

  • 잘못된 핸들러가 제공된다면 .then()은 확정값이 같은 프로미스를 리턴함

 


핸들러 설정하기 (onFulfilled vs onRejected)

 

let prom = new Promise((resolve, reject) => {
  let num = Math.random();
  if (num < .5 ){
    resolve('Yay!');
  } else {
    reject('Ohhh noooo!');
  }
});

const handleSuccess = (resolvedValue) => {
  console.log(resolvedValue);
};

const handleFailure = (rejectionReason) => {
  console.log(rejectionReason);
};

prom.then(handleSuccess, handleFailure);

 

프로미스 상태가 fulfilled가 되면 handleSuccess가 실행되고 rejected가 되면 handleFailure를 호출한다.

 


.catch()

 

코드의 가독성을 위해 다음과 같이 resolved 부분과 rejection 부분을 나눠서 쓸 수 있음

적절한 핸들러가 주어지지 않으면 확정값이 동일한 프로미스를 리턴하는 걸 이용한 것

 

prom
  .then((resolvedValue) => {
    console.log(resolvedValue);
  })
  .then(null, (rejectionReason) => {
    console.log(rejectionReason);
  });

 

이를 더 보기좋게 만들려면 catch()함수를 쓰면 된다 

 

prom
  .then((resolvedValue) => {
    console.log(resolvedValue);
  })
  .catch((rejectionReason) => {
    console.log(rejectionReason);
  });

 

catch()는 하나의 인자만 갖는다.

 


컴포지션 composition

 

프로미스를 연쇄적으로 실행하는 것

각 처리 과정이 서로에게 의존적이거나 실행 순서가 중요할 때 쓰면 좋음

 

firstPromiseFunction()
.then((firstResolveVal) => {
  return secondPromiseFunction(firstResolveVal);
})
.then((secondResolveVal) => {
  console.log(secondResolveVal);
});

 

프로미스를 실행 👉 첫번째 then 실행 👉 두번째 프로미스 리턴 👉 두번째then실행 👉최종 결과값 콘솔에 출력

 

연습문제

 

const {checkInventory, processPayment, shipOrder} = require('./library.js');

const order = {
  items: [['sunglasses', 1], ['bags', 2]],
  giftcardBalance: 79.82
};

checkInventory(order)
.then((resolvedValueArray) => {
  return processPayment(resolvedValueArray);
})
.then((resolvedValueArray) => {
  return shipOrder(resolvedValueArray);
})
.then((successMessage) => {
  console.log(successMessage);
})
.catch((errorMessage) => {
  console.log(errorMessage);
});

 

함수 이름들을 보면 짐작이 가듯이 재고를 확인하고 👉 재고가 있으면 결제로 넘어가고 👉 올바른 결제 정보가 입력됐으면 배송 절차 👉 절차가 완료됐으면 successMessage 표시, 아니면 errorMesage 표시

 

대강 이런식으로 사용된다는 거


Promise.all()

 

복수의 프로미스를 순서 상관없이 가능한 효율적으로 실행하는 것 (concurrency; 동시성)

 

프로미스들의 배열을 인자로 받고 하나의 프로미스를 리턴한다.

리턴되는 프로미스의 상태가 결정되는 방법은 다음과 같다.

  • 모든 배열의 프로미스가 이행 상태면(resolve), Promise.all()이 리턴하는 프로미스는 이행 상태가 되며 각 프로미스들의 resolve value를 배열로 갖게 된다

  • 어떤 배열의 프로미스가 실패 상태면(reject), Promise.all()이 리턴하는 프로미스는 그 즉시 실패 상태가 되며 해당 프로미스의 rejection reason을 갖게 된다. 👉이런걸 failing fast 라고 부름

 

let myPromises = Promise.all([returnsPromOne(), returnsPromTwo(), returnsPromThree()]);

myPromises
  .then((arrayOfValues) => {
    console.log(arrayOfValues);
  })
  .catch((rejectionReason) => {
    console.log(rejectionReason);
  });

 

반응형

관련글 더보기

댓글 영역