TIL JavaScript from Dream Coding(8)

조수경·2022년 5월 30일
0

DreamCoding

목록 보기
8/9
post-thumbnail

Callback

JavaScript is synchronous. (동기)
Execute the code block by orger after hoisting.
hoisting: var, function declaration

console.log('1'); 
setTimeout(() => console.log('2'), 1000); 
console.log('3');

// 1
// 3
// 2

1. Synchronous callback

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

// 1
// 3
// hello
// 2

2. Asynchronous callback

// * 모든 함수의 선언은 호이스팅이 되어 최상단으로 끌어올려진다.
// synchronous callback (동기)
function printImmediately(print) {
  print();
}
// asynchronout callback (비동기)
function printWithDelay(print, timeout) {
  setTimeout(print, timeout);
}
console.log('1'); // 동기
setTimeout(() => console.log('2'), 1000); // 비동기
console.log('3'); // 동기
printImmediately(() => console.log('hello')); // 동기
printWithDelay(() => console.log('async callback!'), 2000); // 비동기

// 1
// 3
// hello
// 2 (1초 후 출력)
// async callback (2초 후 출력)

3. Callback Hell example

class UserStorage {
  loginUser(id, password, onSuccess, onError) {
    setTimeout(() => {
      if (
        (id === 'amanda' && password === 'dream') ||
        (id === 'coder' && password === 'academy')
      ) {
        onSuccess(id);
      } else {
        onError(new Error('not found');
      }
    }, 2000);
  }
  
  getRoles(user, onSuccess, onError) {
    setTimeout(() => {
      if (user === 'amanda') {
        onSuccess({ name: 'amanda', role: 'admin' });
      } else {
        onError(new Error('no access');
      }
    }, 1000}
  }
}


const userStorage = new UserStorage();
const id = propmt('enter your id');
const password = prompt('enter your password');

// LOGIN
userStorage.loginUser(
  id,
  password,
  user => {
    userStorage,getRoles(
      user,
      userWithRole => {
        alert(`Hello ${userWithRole.name}, you have a ${userWithRole.role} role`);
      },
      error => {}
    );
  },
  error => { console.log(error) }
);

콜백 체인의 문제점

  1. 가독성이 떨어진다.
    어디서 어떤식으로 연결되어 있는지 한눈에 가늠하기도 어렵고
    비즈니스 로직을 한눈에 이해하기도 어렵다.
  2. 에러가 발생하거나 디버깅을 해야하는 경우에도 어려움
    문제가 생길 때 체인이 길어지면 길어질수록 디버깅하고 문제를 분석하는 것도 어렵고 유지보수가 힘들다.

Promise

Promise is a JavaScript object for asynchronous operation.
비동기적인 것을 수행할 때 callback 함수 대신에 유용하게 사용할 수 있는 JS Object

state: pending 👉🏻 fulfilled or rejected
Producer vs Consumer

1. Producer

When new Promise is created, the executor runs automatically.

// Promise를 만드는 순간 전달한 excutor라는 콜백함수가 바로 실행된다. 
const promise = new Promise((resolve, reject) => {
  // doing some heavy work (network, read files)
  console.log('doing something...');
  setTimeout(() => {
    resolve('amanda');
    //reject(new Error('no network'));
  }, 2000);
});

2. Consumers: then, catch, finally

promise
  .then(value => {
  console.log(value); 
  // resolve = amanda 
  // reject = Uncaught: (in promise) Error: no network
  })
  .catch(error => {
    console.log(error);
  })
  .finally(() => {
    console.log('finally');
  });
// ** 성공하던 실패하던 상관없이 어떤 기능을 마지막으로 수행하고 싶을 때 finally 사용

3. 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)); // 5

// ** then 에서는 값을 바로 전달해도 되고 또 다른 promise를 전달할 수 있다.

4. 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(getEgg)
  .catch(error => {
    return '🍞'
  })
  .then(cook)
  .then(console.log)
  .catch(console.log);

5. Callback Hell example change using Promise

class UserStorage {
  loginUser(id, password) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (
          (id === 'amanda' && 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 === 'amanda') {
          resolve({ name: 'amanda', role: 'admin' });
        } else {
          reject(new Error('no access');
        }
      }, 1000}
    })
  }
}


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

0개의 댓글