JS STUDY - 4주차 (비동기 해결)

👊0👊·2020년 1월 27일
0

es6 스터디

목록 보기
6/8

외부요청

자바스크립트가 최근에 인기를 끌게된 이유 중 하나는, ajax때문일 것이다. 페이지를 한 번 불러오고 이후로는 자바스크립트를 이용해서 서버와 주고받은 모든 통신을 처리할 수 있으면서, 적은 데이터로 페이지를 다시 랜더링할 수 있게되었기 때문이다. 일련의 분리된 페이지들이 아니라 사실상 웹과 같은 사용자 경험을 얻을 수 있게 되었다. 페이지를 매번 불러오지 않아도 된다면 사용자의 시간과 자원을 정약할 수 있다. 특히 외부 데이터에 접근하는 것은 이른바 단일 페이지 웹 어플리케이션에 매우 중요하다.

자바스크립트는 비동기 언어로, 요청한 데이터를 기다리는 동안 코드 실행을 중단하지 않는다. 자바스크립트는 빠른 웹사이트를 제공하지만 비동기 요청은 다루기 어려울 수 있다.

싱글 스레드

비동기 언어는 그저 이전의 코드가 완전히 해결되지 않아도 이어지는 코드를 실행할 수 있는 언어를 의미한다. 코드 실행이 중단되는 이유를 생각해보자. API에서 데이터를 가져오는 경우가 있을 것이다. DOM이나 다른 곳에서 데이터를 가져올 수도 있다. 또는 상숑자 응답을 기다려야 할 수도 있다.

비동기 언어의 가치는 지연된 정보를 기다리는 동안 이 정보가 필요하지 않은 다른 코드를 실행할 수 있다는 장점이 있다. 지연된 정보를 기다리는 동안 코드가 멈추지 않는다.

그럼 언제 도착할지 모르는 이런 비동기 정보를 깔끔하게 해결할 수 있을까?

콜백함수

프로미스가 등장하기 전에는 콜백 함수를 사용해 비도익 작업을 처리했다.

function getUserPreferences(cb) {
  return setTimeout(() => {
    cb({
      theme: 'dusk',
    });
  }, 1000);
}

function log(value) {
  return console.log(value);
}

log('starting');
// starting

getUserPreferences(preferences => {
  return log(preferences.theme.toUpperCase());
});

log('ending?');
// ending?

// DUSK

콜백함수는 비동기 데이터를 다루기 좋은 방법이다. 문제는 비동기 함수에서 또 비동기 함수를 호출하고, 거기서 또 비동기 함수를 호출해 마침내 너무나 많은 콜백 함수가 중첩되는 경우가 생긴다는 것이다. 이런 경우를 '콜백 지옥'에 빠졌다한다.

만약에 사용자 취향에 맞는 음악 목록을 가져오려면 어떻게 해야할까?

// START:music
function getMusic(theme, cb) {
  return setTimeout(() => {
    if (theme === 'dusk') {
      return cb({
        album: 'music for airports',
      });
    }
    return cb({
      album: 'kind of blue',
    });
  }, 1000);
}
// END:music

// START:hell
getUserPreferences(preferences => {
  return getMusic(preferences.theme, music => {
    console.log(music.album);
  });
});
// END:hell

위의 예제는 두 단계만 중첩되었지만 벌써 가독성이 나빠졌다. 프로미스를 사용하면 콜백 함수문제를 해결할 수 있다.

프로미스

비동기 연결

프로미스는 콜백함수를 인수로 받는 대신에 성공과 실패에 대응하는 메서드를 사용한다. 이렇게 하면 시각적으로 평평해보인다. 게다가 콜백 함수를 중첩하는 대신에 여러 개의 비동기 프라미스를 연결할 수도 있다.

// START:define
function getUserPreferences() {
  const preferences = new Promise((resolve, reject) => {
    resolve({
      theme: 'dusk',
    });
  });
  return preferences;
}
// END:define

// START:pref
getUserPreferences()
  .then(preferences => {
    console.log(preferences.theme);
  });
// 'dusk'
// END:pref

실패처리

또는 실패도 처리할 수 있다.

// START:fail
function failUserPreference() {
  const finder = new Promise((resolve, reject) => {
    reject({
      type: 'Access Denied',
    });
  });
  return finder;
}
// END:fail

// START:catch
failUserPreference()
  .then(preferences => {
  // This won't execute
    console.log(preferences.theme);
  })
  .catch(error => {
    console.error(`Fail: ${error.type}`);
  });
// Fail: Access Denied
// END:catch

연결된 프로미스

콜백으로 중첩되지 않고 평평한 코드를 작성할 수 있게된다.

// START:music
function getMusic(theme) {
  if (theme === 'dusk') {
    return Promise.resolve({
      album: 'music for airports',
    });
  }
  return Promise.resolve({
    album: 'kind of blue',
  });
}
// END:music

// START:chain
getUserPreferences()
  .then(preference => {
    return getMusic(preference.theme);
  })
  .then(music => {
    console.log(music.album);
  });
// music for airports
// END:chain

다음단계

프로미스는 비동기처리를 이전보다 편하게 해주었지만, 도구는 항상 발전한다. ES2017에서는 async/await라는 새로운 방법을 승인했다.

profile
ㅎㅎ

0개의 댓글