비동기 & Promise

devPomme·2021년 2월 1일
0
post-thumbnail

Today I learned

  • 중첩된 callback의 단점, Promise의 장점
  • Promise의 사용 패턴(resolve, reject, then,catch의 관계)
  • Promise에서 인자를 넘기는 방법
  • Promise의 세 가지 상태(pending, fulfilled, rejected)
  • Promise.all 사용법
  • async/await의 작동 원리
  • node.js의 fs 모듈 사용법

callback

Callback error handling Design

const somethingGonnaHappen = callback => {
  waitingUntilSomethingHappens()
  
  if (isSomethingGood) { // 정상적으로 작동될 때
    callback(null, something) // 에러=null, 데이터는 값
  }
  
  if (isSomethingBad) { // 에러가 발생할 때
    callback(something, null) // 에러=에러 객체, 데이터는 null
  }
}

콜백 중첩의 문제점

콜백지옥

코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어지는 현상

step1(function (value1) {
    step2(function (value2) {
        step3(function (value3) {
            step4(function (value4) {
                step5(function (value5) {
                    step6(function (value6) {
                        // Do something with value6
                    });
                });
            });
        });
    });
});

더 공부할 것(비동기 요청/callback으로 발생하는 안티패턴)

  • 비동기 대 비동기(혹은 비동기 대 동기) 간 경쟁관계 발생
  • 비동기 결과값을 사용하는 여러 분기가 존재하는 경우
  • 에러 분기에 대한 처리
  • 믿음성 문제

Promise

  • 비동기 작업을 추상화한 객체

생성자

Promise() 프로미스를 지원하지 않는 함수를 감쌀 때 사용

메서드

Promise.all(iterable): 모든 프로미스가 이행한 뒤 이행하고, 어떤 프로미스가 거부하면 즉시 거부하는 프로미스를 반환(모 아니면 도 상황)

promise를 배열로 받아 병렬 처리를 한다.

Promise.allsettled()
성공이나 실패 상관없이 이행이 된다. 하나가 실패하더라도 다른 프로미스들은 사용해야할 때 쓰면 좋다.

finally()와의 차이점

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); // Array [3, 42, "foo"]
});

Promise.reject(): 주어진 이유(reason)로 거부된 Promise 객체를 반환

Promise.resolve(): 주어진 값으로 이행하는 Promise.then 객체를 반환

Promise 프로토타입

Promise.prototype.catch()
프로미스 에러 처리는 가급적 catch()를 사용해야한다!

// handleSuccess()의 오류를 처리해 줄 함수가 없음.
save().then(
  handleSuccess,
  handleError //
);

then()의 첫번째 콜백 함수 내부에서 오류가 나는 경우 오류를 제대로 잡지 못한다. (Uncaught Error)

// handleSuccess()의 오류 발생시 에러 헨들러 실행
save()
  .then(handleSuccess)
  .catch(handleError)
;

Promise.prototype.then()


함수가 값을 반환할 경우, then에서 반환한 프로미스는 그 반환값을 자신의 결과값으로 하여 이행합니다.

값을 반환하지 않을 경우, then에서 반환한 프로미스는 undefined를 결과값으로 하여 이행합니다.

오류가 발생할 경우, then에서 반환한 프로미스는 그 오류를 자신의 결과값으로 하여 거부합니다.

이미 이행한 프로미스를 반환할 경우, then에서 반환한 프로미스는 그 프로미스의 결과값을 자신의 결과값으로 하여 이행합니다.

이미 거부한 프로미스를 반환할 경우, then에서 반환한 프로미스는 그 프로미스의 결과값을 자신의 결과값으로 하여 거부합니다.

대기 중인 프로미스를 반환할 경우, then에서 반환한 프로미스는 그 프로미스의 이행 여부와 결과값을 따릅니다.


MDN - Promise.prototype.then()

  • 비동기 작업의 결과(완료/실패/결과값)
    • 대기(pending): 초기 상태
new Promise();

new Promise(function(resolve, reject) {
});
  • 이행(fulfilled): 연산 성공
function getData() {
  return new Promise(function(resolve, reject) {
    let data = 100;
    resolve(data);
  });
}

이행 상태에서는 then()을 이용해서 처리 결과값을 받는다.

  getData().then(function(resolvedData) {
  console.log(resolvedData); // 100
});
  • 거부(rejected): 연산 실패
    실패 처리의 결과값은 catch()로 받는다.
function getData() {
  return new Promise(function(resolve, reject) {
  reject(new Error("Request is failed!"));
});
}
// reject()의 결과값 Error를 err에 받음
getData().then().catch(function(err) {
  console.log(err); //Error: Request is failed!
});

Async & await

Promise Hell

connectToDatabase()
    .then((database) => {
        return getUsers(database)
            .then((users) => {
                return getUserSettings(database)
                    .then((settings) => {
                        return enableAccess(user, settings);
        });
    });
});

Promise와의 차이점

비동기 코드의 겉모습과 동작을 좀 더 동기 코드와 유사하게 만든다.
코드가 간결해지고 가독성이 높아진다.

Promise를 이용한 비동기요청 처리
const users = () => {
  getUsers()
      .then(users => {
          console.log(users);
    	  return users;
  })
  .catch(error => {
    
  });
}      

⇒ getUsers() 메소드는 promise 객체를 리턴하고, JSON 객체가 resolve된다.

Async, Await을 이용한 비동기요청 처리
  • 함수를 선언할 때는 async를 붙여준다.
    async는 함수가 항상 ``Promise```를 반환하게 만들어준다.
  • awaitasync 함수 안에서만 작동한다.
    await은 넘겨진 Promise가 이행되기를 기다렸다가 해당 값을 리턴한다.
const users = async() => {
  console.log(await getUsers());
  return await getUsers;

js event loop

  • heap: 변수들의 데이터가 저장된 곳
  • stack: 함수들이 실행될 때 렉시컬 환경이 저장되는 곳
  • Web API: 브라우저에서 지원해주는 기능들
  • Callback Queue: Web API에서 실행 완료된 친구들이 줄 서서 기다리는 곳
  • Event Loop: 콜 스택이 비어있으면 콜백 큐에서 기다리느 친구들을 하나씩 가져오는 친구
async function f1() {
  await new Promise(resolve => setTimeout(resolve, 1000));
  return '첫번째'; // (1)
}

function f2() {
  f1().then(result => console.log(result)); // (3)
  console.log('두번째'); // (2)
}

f2();
// "두번째"
// "첫번째"
profile
헌신하고 확장하는 삶

0개의 댓글