JavaScript 9. 비동기

khxxjxx·2021년 5월 10일
0

드림코딩 by 엘리

목록 보기
9/11

강좌 : 유튜브 드림코딩 by 엘리

9. 비동기

📄 Callback

  • 자바 스크립트는 동기적이다
  • hoisting이 된 이후부터 코드가 나타나는 순서대로 실행된다

setTimeout

  • setTimeout( handler, Timeout )
// 예시
console.log('1');
setTimeout(() => console.log('2'), 1000);  // 1초가 지나면 실행한다
console.log('3');1, 3, 2

✍️Synchronous callback

// 예시
function printImmediately(print) {
  print();
}
printImmediately(() => console.log('hello'));

✍️Asynchronous callback

// 예시
function printWithDelay(print, timeout) {
  setTimeout(print, timeout);
}
printWithDelay(() => console.log('async callback'), 2000);2초뒤에 'async callback' 출력

✍️Callback Hell example

// 예시
class UserStorage {
  loginUser(id, password, onSuccess, onError) {
    setTimeout(() => {
      if (
        (id === 'hxxjxx' && password === 'dream') ||
        (id === 'coder' && password === 'academy')
      ) {
        onSuccess(id);
      } else {
        onError(new Error('not found'));
      }
    }, 2000);
  }

  getRoles(user, onSuccess, onError) {
    setTimeout(() => {
      if (user === 'hxxjxx') {
        onSuccess({ name: 'hxxjxx', role: 'admin' });
      } else {
        onError(new Error('no access'));
      }
    }, 1000);
  }
}

const userStorage = new UserStorage();
const id = prompt('enter your id');
const password = prompt('enter your passrod');
userStorage.loginUser(
  id,
  password,
  user => {
    userStorage.getRoles(
      user,
      userWithRole => {
        alert(
          `Hello ${userWithRole.name}, you have a ${userWithRole.role} role`
        );
      },
      error => {
        console.log(error);
      }
    );
  },
  error => {
    console.log(error);
  }
);

📄 Promise

  • JavaScript에서 제공하는 비동기를 간편하게 처리할 수 있도록 도와주는 Object
  • 정해진 장시간의 기능을 수행하고 나서 정상적으로 기능이 수행이 되어졌다면 성공의 메세지와 함께 처리된 결과값을 전달
  • 만약 기능을 수행하다가 예상치 못한 문제가 발생했다면 에러를 전달

state

  • pending -> fulfilled or rejected

Producer

  • 원하는 기능을 수행해서 해당하는 데이터를 만들어 낸다
  • promise가 만들어진 순간 그 안에 전달한 executor 함수가 자동적으로 실행된다
  • resolve : 기능을 정상적으로 수행해서 마지막에 최종 데이터를 전달
  • reject : 기능을 수행하다가 중간에 문제가 생기면 호출
// 예시
const promise = new Promise((resolve, reject) => {
  // doing some heavy work (net work, read files)
  console.log('doing something...');
  setTimeout(() => {
    // resolve('hxxjxx');
    reject(new Error('no network'));
  }, 2000);
});

Consumer

  • 원하는 데이터를 소비하는 것
  • .then : 값이 정상적으로 수행되서 마지막에 최종적으로 resolve라는 콜백함수를 통해서 전달한 이 값이 value의 파라미터로 전달
  • then은 값을 바로 전달해도 되고 또다른 비동기인 promise를 전달해도 된다
  • .catch : 에러가 발생했을 때 처리 할 값
  • .finally : 성공하든 실패하든 상관없이 무조건 마지막에 호출
// 예시
promise
  .then(value => {
    console.log(value);
  })
  .catch(error => {
    console.log(error);
  })
  .finally(() => {
    console.log('finally');
  });

✍️Promise chaining

// 예시
const fetchNumber = new Promise((resolve, reject) => {
  setTimeout(() => resolve(1), 1000);
});

fetchNumber
  .then(num => num * 2)
  .then(num => num * 3)
  .then(num => {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(num - 1), 1000);
    });
  })
  .then(num => console.log(num));

✍️Error Handling

// 예시
const getHen = () =>
  new Promise((resolve, reject) => {
    setTimeout(() => resolve('🐓'), 1000);
  });
const getEgg = hen =>
  new Promise((resolve, reject) => {
    setTimeout(() => reject(new Error(`error! ${hen} => 🥚`)), 1000);
  });
const cook = egg =>
  new Promise((resolve, reject) => {
    setTimeout(() => resolve(`${egg} => 🍳`), 1000);
  });

getHen() // 한가지만 받아서 인자하는 경우에는 생략이 가능하다
  .then(hen => getEgg(hen)) // .then(getEgg)
  .catch(error => '🥖')  // 계란을 받아오는데 오류가 생겼지만 빵을 대신 전달
  .then(egg => cook(egg)) // .then(cook)
  .then(meal => console.log(meal)) // .then(console.log);
  .catch(console.log);  // error! 🐓 => 🥚
// 중간에 catch를 사용하지 않으면 계란을 받아오는 도중에 오류가 발생해 요리가 완성되지 못한다🥖 => 🍳

✍️Callback to promise

// Callback Hell example
class UserStorage {
  loginUser(id, password) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (
          (id === 'hxxjxx' && password === 'dream') ||
          (id === 'coder' && password === 'academy')
        ) {
          resolve(id);
        } else {
          reject(new Error('not found'));
        }
      }, 2000);
    });
  }

  getRoles(user) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (user === 'hxxjxx') {
          resolve({ name: 'hxxjxx', role: 'admin' });
        } else {
          reject(new Error('no access'));
        }
      }, 1000);
    });
  }
}

const userStorage = new UserStorage();
const id = prompt('enter your id');
const password = prompt('enter your passrod');
userStorage
  .loginUser(id, password)
  .then(userStorage.getRoles)
  .then(user => alert(`Hello ${user.name}, you have a ${user.role} role`))
  .catch(console.log);

📄 Async & Await

async

  • async 키워드를 함수앞에 쓰면 번거롭게 promise를 쓰지 않아도 자동적으로 함수안에 있는 코드 블럭들이 promise로 변환
// 예시
async function fetchUser() {
  // do network reqeust in 10 secs...
  return 'hxxjxx';
}

const user = fetchUser();
user.then(console.log);

await

  • async 붙은 함수 안에서 사용할 수 있다
// 예시
function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function getApple() {
  await delay(2000);
  return '🍎';
}

async function getBanana() {
  await delay(1000);
  return '🍌';
}

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

pickFruits().then(console.log);

병렬처리

  • 서로 연관이 되어있지 않은 데이터의 경우 서로를 기다릴 필요가 없으므로 병렬처리해줘야 효율적이다
// 예시
// 밑의 코드는 지저분하므로 API를 사용해서 병렬적으로 처리한다
async function pickFruits() {
  const applePromise = getApple();
  const bananaPromise = getBanana();
  const apple = await applePromise;
  const banana = await bananaPromise;
  return `${apple} + ${banana}`;
}

pickFruits().then(console.log);

✍️useful APIs

all

  • 병렬적으로 값을 전달
// 예시
function pickAllFruits() {
  return Promise.all([getApple(), getBanana()]).then(fruits =>
    fruits.join(' + ')
  );
}
pickAllFruits().then(console.log);

race

  • 배열에 전달된 promise중에서 가장먼저 값을 return하는 값만 전달
// 예시
function pickOnlyOne() {
  return Promise.race([getApple(), getBanana()]);
}
pickOnlyOne().then(console.log);
profile
코린이

0개의 댓글