JavaScript/node.js

TIL 1109 Promise async&await JSON.parse

짱닭 2020. 11. 10. 21:40
반응형

Promise 객체

Promise.. 그것은 약속이다. 어떤약속이냐
웹에서
데이터를 얻어서 보내주거나
얻지 못한다면 (에러발생시) 이유와 함께
에러를 발생시키도록한 약속!

.then() 은 Promise 객체 내에서 resolve()에 전달된 데이터를 받는다.

.catch() 는 Promise 객체 내에서 에러 발생시 reject()에 전달된 데이터를 받는다.

Promise의 3가지 상태

  • Pending (대기)
  • Fulfilled (완료)
  • Rejected (거부)

순서도

  1. pending
    1-1 -resolve-> 2. fulfilled (settled)
    1-2 -rejec-> 2. pending (settled)

Promise 객체는 이벤트 루프에서 대기상태를 유지하다가
실행순서가 되면 비동기적으로 실행되고
실행 중 오류가 발생하지 않으면 resolve()를 통해서 완료 상태(fulfilled)가 된다.

오류가 발생하면 reject()에 구현된 코드에 따라 오류 처리를 하게 된다.

JSON.parse

string 을 json 객체로 변환시켜주는 메서드.
fs.readFilej()이 파일 내용을 string 으로 가져오기 때문에
사용하기 위해 파일 내용을 json으로 변환시킬 때 사용.

const json = '{"result":true, "count":42}';
const obj = JSON.parse(json);

console.log(obj.count);
// expected output: 42

console.log(obj.result);
// expected output: true

Promise.resolve()

주어진 값으로 이행하는 Promise.then 객체를 반환합니다. 그 값이 프로미스인 경우, 해당 프로미스가 반환됩니다

resolve()로 값을 전달해주지 않으면 Promise의 state가 pending에서 변하지 않는다.
resolve()를 사용하고 종료된다면 state는 fulfilled 된다.

const promise1 = Promise.resolve(123);
//or
const promise1 = new Promise((resolve, reject) => {
  resolve(123);
});

//then의 인자로 resolve의 인자(123)가 들어간다.
promise1.then((value) => {
  console.log(value);
  // expected output: 123
});

//아래처럼 배열도 인자로 사용가능.
var p = Promise.resolve([1,2,3]);
  p.then(function(v) {
  console.log(v[0]); // 1
});

파라미터가 1개일때 함수이름만 쓰면, 암묵적으로 함수의 매개변수로 전달 됨

  getHen()
   .then(getEgg)
   .then(cook)
   .then(console.log);

Promise.reject()

거부된 Promise 객체를 반환합니다.

아래처럼 에러가 발생한 경우 reject로 객체를 넘긴다.

const promise1 = new Promise((resolve, reject) => {
    fs.readFile(filePath, 'utf8', (err, data)=>{
      if(err) {
        reject(err)
      }else {
        resolve(data)
      }
    });
  });

promise1.then(value => console.log(value));
//에러 발생시 에러가 콘솔창에 찍힌다.

Promise.catch()

Promise 객체를 리턴하며, reject 된 케이스만 다룬다.
즉, 에러가 발생한 경우에만 호출된다.

const promise1 = new Promise((resolve, reject) => {
  throw 'Uh-oh!';
});

promise1.catch((error) => {
  console.error(error);
});
// expected output: Uh-oh!

.then()으로 체이닝하며 일련의 과정을 수행시켰을 경우,
수행 과정 중 에러가 발생했을 때
.catch()내부의 콜백함수가 실행되어서 에러핸들링을 하게 된다.
에러가 발생한 뒤의 .then()은 수행되지 않는다.

끝까지 에러가 발생하지 않으면 마지막 .then()까지 실행하고
.catch()는 실행하지 않는다.

Promise.finally()

.then()이나 .catch() 가 모두 호출되면 마지막에 반드시 호출된다.

promise
  .then((value) => {
    console.log(value);
  })
  .catch(error => {
    console.log(error);
  })
  .finally(() => { // 성공하든 실패하든 마지막에 실행됨
    console.log(`finally`);
  })

Promise.all()

Promise 객체 배열을 인자로 받아서,
인자로 받은 Promise를 모두 병렬적으로 동시에 실행하고,
모든 Promise가 호출이 끝나기까지 기다렸다가 결과를 한번에 반환한다.

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]

아래는 async function으로 병렬적으로 호출하는 방법 (Promise.all()을 쓰는게 더 좋다.)

function delay(ms){
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function getApple() {
  await delay(1000);
  return 'Apple';
}

async function getBanana() {
  await delay(2000);
  return 'Banana';
}

async function pickFruits() {
  const applePromise = getApple();
  const bananaPromise = getBanana();
  const apple = await applePromise;
  const banana = await bananaPromise;
  return `${apple} + ${banana}`;
}

pickFruits().then(console.log);
//Promise 두개가 병렬적으로 실행되므로 3초 뒤가 아니라 2초 뒤에 'Apple + Banana'가 출력됨


//Promise.all 을 사용하면

function pickAllFruits() {
  return Promise.all([getApple(), getBanana()])
    .then(fruits => fruits.join(' + ')); //fruits === ['Apple', 'Banana']
}

pickAllFruits().then(console.log);


//병렬적으로 호출했을 때 가장 먼저 완료되는 Promise를 출력하기
function pickFastOne() {
  return Promise.race([getApple(), getBanana()]);
}

pickFastOne().then(console.log);
//Banana보다 짧은 시간이 걸리는 Apple만 출력된다.

참고 : 드림코딩by엘리

async function ( async & await )

function에 async만 붙여주면 Promise 객체를 리턴하는 함수로 만들 수 있다! like Magic!

에러 처리는 try ~ catch 구문을 이용해야 한다

 function resolveAfter2Seconds() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('resolved');
    }, 2000);
  });
}

async function asyncCall() {
  console.log('calling');

  try {
    const result = await resolveAfter2Seconds();
  } catch(error) {
    console.log(error);
  }

  console.log(result);
  // expected output: "resolved"
}

asyncCall();

await

await 키워드는 Promise를 기다리기 위해 사용됩니다.
async function 내부(코드블럭)에서만 사용할 수 있다.

Promise 객체를 리턴하는 함수는(async 키워드가 안붙어도)
모두 await로 완료를 기다리게 만들 수 있다.

function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

async function f1() {
  var x = await resolveAfter2Seconds(10); //x 에는 resolve(x)로 리턴된 x 가 할당된다.
  //Promise객체를 리턴하는 함수이므로 await로 비동기적으로 함수실행하고 종료는 동기적으로 기다리게 만들 수 있다.
  console.log(x); // 10
  //console.log(x)는 await를 기다렸다가 호출된다.
}

f1();
//10초 뒤에 10이 콘솔에 찍힘

아래는 await을 안쓴 경우와 쓴 경우

fetch('http://www.naver.com/data.json')
.then(response => response.json())
.then(json => {
  console.log(json)
})

async function request() {
  let response = await fetch('http://www.naver.com/data.json')
  let json = await response.json()
  console.log(json)
}

additional

- node.js 와 브라우저의 공통점 Promise 객체 사용가능.

- 브라우저에선 fs.readFile 못쓰고 node.js 에서 가능.

- node.js에는 fetch()가 없다. 3rd party 사용해야함.

반응형