[마스터 개념] 7 | 프로미스

728x90

[마스터 개념] 7 | 프로미스

1 variable 변수

2 operator 연산자

3 function 함수

4 object 객체

5 class 클래스

7 built-in 빌트인 객체

8 array 배열

9 iterator 이터러블

10 map

11 more-operators 유용한 연산자들

12 module 모듈

13> promise 프로미스

14 scope 스코프

15 prototype 프로토타입

16 closure 클로져

17 this 

13 promise 프로미스

callstack

 

 자바스크립트는 동기적으로 수행된다. 따라서 무겁고 오래 걸리는 작업을 수행하기에는 적합하지 않다.

 

 동기적 : 직렬, 작업이 종료될 때까지 기다린 후 다음 작업을 수행하는 방식

 비동기적 : 병렬, 다른 작업을 하고 있다가, 요청했던 작업이 종료되면 추가 작업을 수행하는 방식

 

 비동기적으로 수행하려면,

 1. JavaScript Runtime Environment 에서 비동기적으로 처리하는 API 를 사용하여 원하는 callback 함수를 비동기적으로 작업

 2. 그 작업을 마치면 그 callback 함수를 task queue 에 넣음

 3. call stack 과 task queue 를 감시하는 event loop 가 call stack 이 비어있는 경우에 task queue 에 있는 callback 함수를 call stack 로 가져옴

 

function execute() {
  console.log("1");
  setTimeout(() => {
    console.log("2");
  }, 3000);
  console.log("3");
}

execute();	// 1
		// 3
		// 2

 

setTimeout( ) : 콜백함수를 지정된 시간(밀리초) 후에 실행하는 비동기 함수

 

1. execute( ) 실행

2. 1 출력

3. setTimeout( ) 비동기 함수 실행 -> 해당 콜백함수 비동기로 실행

4. 콜백함수는 비동기로 작업하고 있고, 다음 작업인 3 출력 -> call stack 비어있음

5. 콜백함수 작업 끝나면 task queue 에 넣고, call stack 이 비어있으니 콜백함수 call stack 에 가져와서 2 출력

 

Promise 프로미스

 

 비동기적으로 처리할 수 있도록 도와주는 Promise 객체가 있다.

 

function runInDelay(seconds) {
  return new Promise((resolve, reject) => {
    if (!seconds || seconds < 0) {
      reject(new Error("seconds 가 없거나 0보다 작음"));
      }
    setTimeout(resolve, seconds * 1000);
  });
}

runInDelay(2)
  .then(() => console.log("타이머 완료!!"))
  .catch(console.error)
  .finally(() => console.log("끝났다"));

 

 runInDelay( ) 함수는 setTimeout( ) 함수에서의 밀리초를 초로 바꾼 함수이다.

 

 최종적으로 프로미스로 만든 runInDelay( ) 를 호출하면 

 .then(성공하면 호출됨. 필요한 일을 수행)

 .catch(실패하면 호출됨. 에러를 잡음)

 .finally(성공 and 실패 시 호출됨. 최종적으로 수행)

 

 runInDelay( )를 프로미스로 만들려면 new Promise( ) 객체를 반환해야 하는데, 이 프로미스 객체 안에서는 비동기적으로 처리된다.

 

 새로운 프로미스 객체는

 성공할 때, then 을 호출할 때 실행할 reslove( ) 와

 실패할 때, catch 를 호출할 reject( ) 이렇게 2개의 인자를 갖는다.

 

 이때, reject( ) 에는 new Error( ) 처럼 새로운 에러를 만들어 줘야 한다.

 

// 1초 뒤 바나나
function getBanana() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("바나나");
    }, 1000);
  });
}

// 3초 뒤 사과
function getApple() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("사과");
    }, 3000);
  });
}

// 오렌지는 없음. error 발생
function getOrange() {
  return Promise.reject(new Error("no orange"));
}

 

// 바나나와 사과 같이 가져오기
getBanana() 
  .then((banana) =>
    getApple()
      .then((apple) => [banana, apple])
  )
  .then(console.log);		// [ '바나나', '사과' ]  4초 뒤

 

 getBanana( ) 는 Promise 지만 바나나를 가져온 다음, 사과를 가져와 동기적으로 처리된다. 따라서 총 1초 + 3초 = 4초가 소요된다.

 

Promise.all([getBanana(), getApple()])
  .then((fruits) => console.log("all", fruits));	// all [ '바나나', '사과' ]  3초 뒤
  
Promise.all([getBanana(), getApple(), getOrange()])
  .then((fruits) => console.log("all-error", fruits))
  .catch(console.log);					// X
  
Promise.allSettled([getBanana(), getApple(), getOrange()]) 
  .then((fruits) => console.log("all-settle", fruits))
  .catch(console.log);		
  
// all-settle [
//  { status: 'fulfilled', value: '바나나' },
//  { status: 'fulfilled', value: '사과' },
//  {
//    status: 'rejected',
//    reason: Error: no orange
//        at getOrange (C:\Users\...)
//        at Object.<anonymous> (C:\Users\...)
//        at Module._compile (node:internal/modules/cjs/loader:1105:14)
//        at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
//        at Module.load (node:internal/modules/cjs/loader:981:32)
//        at Function.Module._load (node:internal/modules/cjs/loader:822:12)       
//        at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
//        at node:internal/main/run_main_module:17:47
//    }
//  ]

 

 Promise.all 은 병렬적으로 한 번에 모든 Promise 들을 실행한다. 따라서 총 1초, 3초 = 3초가 소요된다.

 

 하지만 error 를 발생시키는 getOrange( ) 가 있어서 catch 를 해줘도 then 이 실행되지 않으므로 "all-error" 는 출력되지 않는다. 따라서 성공한 것만 가져올 수 있다.

 

 Promise.allSettled 는 주어진 Promise 의 결과를 모두 받아볼 수 있다.

 

Promise.race([getBanana(), getApple()]) 
  .then((fruits) => console.log("race", fruits));	// race 바나나

 

 Promise.race 는 주어진 Promise 중 제일 빨리 수행된 것이 이기며 빠른 것만 가져온다. 따라서 1초 < 3초 = 1초가 소요된다.

 

async await

 

// 바나나와 사과 같이 가져오기
getBanana() 
  .then((banana) =>
    getApple()
      .then((apple) => [banana, apple])
  )
  .then(console.log);		// [ '바나나', '사과' ]

 

 중첩된 콜백함수는 지저분하고 가독성이 떨어진다.

 

// 바나나와 사과 같이 가져오기
async function fetchFruits() {
  const banana = await getBanana();
  const apple = await getApple();
  return [banana, apple];
}
fetchFruits()
  .then((fruits) => console.log(fruits));  // [ '바나나', '사과 ]

 

 따라서 비동기 함수 앞에 'async' 키워드를 붙이면 함수 내부에서 동기적으로 처리할 수 있다.

 

 Promise 를 반환하는 함수를 호출할 때는 await 를 사용하여 비동기적으로 처리하는데, resolve 되면 그 값을 변수에 할당한다.

 

 그냥 반환값만 있을 때는 반환값을 reslove 하는 Promise 가 만들어진다.

 

JSON

 

 Json (JavaScript Object Notation) : 서버와 클라이언트(브라우저, 모바일) 간의 HTTP 통신을 위한 오브젝트 형태의 텍스트 포맷

 

 stringify(object) -> JSON : 직렬화 Serializing, 객체를 문자열로 변환, 데이터만 포함, 함수 포함 X

 parse(JSON) -> object : 역직렬화 Deserializing, 문자열 데이터를 자바스크립트 객체로 변환

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90