ES6에서 추가된 새로운 문법 2 Promises, async&await

7477 단어 ES6node.jsES6

--> 일반적으로 자바스크립트는 가벼움을 위해 비동기이므로 값의 반환과 상관없이 진행됨
--> 따라서 순차적으로 진행되어야만 하는 특정부분들에서는 동기 처리가 필요함 (외부에서 데이터를 가져온 후 처리하는 부분 등등)

동기
--> 요청과 그 결과가 한 자리에서 동시에 일어남
--> 요청을 하면 시간이 얼마나 걸리든지 결과를 받아야 함
--> A노드와 B노드 사이의 작업 처리 단위를 맞추겠다는 뜻

비동기
--> 요청과 그 결과가 한자리에서 일어나지 않음
--> 요청한 자리에서 결과가 주어지지 않음
--> 노드 사이의 작업 처리 단위를 맞추지 않아도 된다는 뜻

Promises

--> 비동기를 동기 방식으로 처리할 때 주로 사용되는 문법

기존의 비동기 처리를 할 떄 발생했던 콜백지옥 해결

--> 비동기를 동기로 만드는 작업을 비동기 처리라고 한다.

기존의 콜백 지옥

 isBusHere(function(isBusHereResult) {
  isBusStop(isBusHereResult, function(isBusStopResult) {
    isDoorOpen(isBusStopResult, function(isDoorOpenResult) {
      findWallet(isDoorOpenResult, function(isWalletHere) {
        findCard(isWalletHere, function(isCardHere) {
          payBusFare(isCardHere, function() {
            // 드디어 결제가 성공했네요...
          }, failureCallback);
        }, failureCallback);
      }, failureCallback);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);

--> 위의 코드처럼 콜백이 끊임 없이 나타나 가독성이 매우 떨어지게 된다.

Promises 사용

    isBusHere()
.then(function(isBusHereResult) {
    return isBusStop(isBusHereResult)
})
.then(function(isBusStopResult) {
    return isDoorOpen(isBusStopResult)
})
.then(function(isDoorOpenResult) {
    return findWallet(isDoorOpenResult)
})
.then(function(isWalletHere) {
    return findCard(isWalletHere)
})
.then(function(isCardHere) {
    return payBusFare(isCardHere)
})
.catch(failureCallback);

--> 가독성이 좋아졌음

Promises에 arrowFunction 적용하여 사용

isBusHere()
  .then(isBusHereResult => isBusStop(isBusHereResult))
  .then(isBusStopResult => isDoorOpen(isBusStopResult))
  .then(isDoorOpenResult => findWallet(isDoorOpenResult))
  .then(isWalletHere => findCard(isWalletHere))
  .then(isCardHere => payBusFare(isCardHere))
  .catch(failureCallback);
  

--> 가독성이 매우 좋아졌음

Promises 예제

const isReady = true;
// 1. Producer
const promise = new Promise((resolve, reject) => {
  console.log("Promise is created!");
  if (isReady) {
    resolve("It's ready");
  } else {
    reject("Not ready");
  }
});

// 2. Consumer
promise
  .then(messsage => {
    console.log(messsage);
  })
  .catch(error => {
    console.error(error);
  })
  .finally(() => {
    console.log("Done");
  });

// Promise is created!
// It's ready
// Done
  1. promise 함수 생성

  2. resolve 함수를 통해 정상 작동되었음을 나타내며, resolve함수의 요소를 promise 함수가 사용될 때 then의 매개변수에 전달
    --> 위의 경우 resolve의 요소 "It's ready"를 then의 매개변수 message에 할당하여 then이 실행됨

  3. reject 함수를 통해 문제가 생겼음을 나타내며, reject 함수의 요소를 promise 함수가 사용될 때 catch의 매개변수에 전달
    --> 위의 경우, 만약 isReady가 false였을 경우,
    reject의 요소 "Not ready"를 catch의 매개변수 error에 할당하여 catch가 실행됨

==> 즉 resolve일 경우 then으로, reject일 경우 catch로 감 finally는 항상 실행

Promise의 상태 (3가지)

바로 위의 함수 예시

1.Pending(대기)

--> 아래와 같이 Promise가 처음 생성되면 promise의 상태는 pending(대기)상태가 됨

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

  console.log(promise);

  // Promise { <pending> }

2. Fulfilled(이행)

--> 아래와 같이 Promise에서 resolve를 실행하면 Fulfilled(이행)상태가 됨
--> Promise가 정상적으로 실행되었을 때 resolve 사용

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

console.log(promise);

// Promise {<fulfilled>: undefined}

3. Rejected(실패)

--> Promise에서 reject를 실행하면 Rejected(실패)상태가 됨
--> 정상적으로 실행되지 않음 --> 잘못된 것을 알리기 위해 reject 사용

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

console.log(promise);

//Promise {: undefined}

Promise의 구성 --> Producer와 Consumer

Producer

Promise를 처음 생성할때 Promise의 내부 코드블럭이 실행됩니다. 이를 executor라 하는데, executor 실행 결과에 따라 resolve 혹은 reject를 불러줍니다.

  const isReady = true;
// 1. Producer
const promise = new Promise((resolve, reject) => {
    // executor
  console.log("Promise is created!");
  if (isReady) {
    resolve("It's ready");
  } else {
    reject("Not ready");
  }
});

// Promise is created!

Consumer

Promise의 결과에 따라 후처리를 하는 부분입니다. Promise가 정상적으로 실행되어 resolve가 되었으면 then을 통해 후처리가 가능하고, reject가 될 경우 catch를 통해 후처리가 가능합니다.

  const isReady = true;
// 1. Producer
const promise = new Promise((resolve, reject) => {
  console.log("Promise is created!");
  if (isReady) {
    resolve("It's ready");
  } else {
    reject("Not ready");
  }
});

// 2. Consumer
promise
    // promise에서 resolve가 될경우
  .then(messsage => {
    console.log(messsage);
  })
    // promise에서 reject가 될경우
  .catch(error => {
    console.error(error);
  })

// Promise is created!
// It's ready

async, await

--> premise를 더 쉽게 사용하게 해줌
--> 즉 더 쉽게 동기로 만들 수 있음

    async function f() {
    return 1;
  }

--> 함수 앞에 async를 붙이면 항상 프라미스를 반환
--> 프라미스가 아닌 값을 반환하더라도 이행 상태의 프라미스(resolved promise)로 값을 감싸 이행된 프라미스가 반환되도록 만듬

--> 자바스크립트는 await키워드를 만나면 프라미스가 처리 될때까지 기다리고 결과는 그 이후 반환됨

   async function f() {

  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("완료!"), 1000)
  });

  let result = await promise; // 프라미스가 이행될 때까지 기다림 (*)

  console.log(result); // "완료!"
}

f();

--> 일반적으로 자바스크립트는 편의성을 위해 비동기이므로 값의 반환과 상관없이 진행됨

--> 이것을 프라미스를 사용하여 then, catch등을 통해 동기로 만들어 줬던 것

but
--> await를 걸어주는 것으로 프라미스가 값을 반환할 때까지 기다렸다가 값을 반환하면 진행 --> 위의 코드에선 프라미스가 1초 뒤에 값을 반환하므로 1초 뒤에 진행

--> 좀더 손쉽게 동기 처리가 가능해짐

async await 예시 )

  async function showAvatar() {

  // JSON 읽기
  let response = await fetch('/article/promise-chaining/user.json');
  let user = await response.json();

  // github 사용자 정보 읽기
  let githubResponse = await fetch(`https://api.github.com/users/${user.name}`);
  let githubUser = await githubResponse.json();

  // 아바타 보여주기
  let img = document.createElement('img');
  img.src = githubUser.avatar_url;
  img.className = "promise-avatar-example";
  document.body.append(img);

  // 3초 대기
  await new Promise((resolve, reject) => setTimeout(resolve, 3000));

  img.remove();

  return githubUser;
}

showAvatar();

--> 데이터를 읽어온 다음(결과가 반환된 다음) 처리해야 되기 떄문에 동기 방식으로 처리할 필요성이 있음
--> async await를 사용하여 결과가 반환될 때까지 기다렸다가 진행되도록 동기 처리
--> promise 보다도 손쉽게 동기 처리가 가능함

좋은 웹페이지 즐겨찾기