동기 && 비동기

hyo·2022년 10월 22일
0

[Javascript] 기초 학습

목록 보기
62/62

callback

// callback으로 비동기 만들기 
class UserStorage {
  loginUser(id, password, onSuccess, onError){
    setTimeout(() => {
      if(
        (id === 'hyo' && password === '0416') || 
        (id === 'woo' && password === '0715')
        ){
        onSuccess(id);
      }
      else {
        onError(new Error('not found'))
      }
    }, 5000)
  }

  getRoles(user, onSuccess, onError){
    setTimeout(() => {
      if(user === 'hyo'){
        onSuccess({name: 'hyo', role: 'admin'});
      }
      else {
        onError(new Error('no access'));
      }
    }, 1000);
  }
}
// 
const userLogin = new UserStorage();
const id = prompt('id를 입력하시오');
const password = prompt('password를 입력하라');

userLogin.loginUser(
  id, 
  password,
  (user) => { 
    userLogin.getRoles(user,
      (userInfo) => {
        alert(`Hello ${userInfo.name}님 반가워요`)
      }
    ), 
    (error) => {
      alert('Error')
    }
  },
  (error) => {
    alert('error')
  }
)

실행을 시키면 alert()함수를 썻기에 바로 입력창이 뜨며
id로 'hyo', password로 '0416'을 누르니 콘솔창에 'Hello Hyo님 반가워요'라고 잘 뜨는걸 확인할 수 있다.

Promise

// 1. Producer
const promise = new Promise((resolve, reject) => { // Promise(re,re) -> resolve,reject 라는 executor라는 콜백함수 인자 2개가 존재
  console.log('doing something...')
  setTimeout(() => {
    // resolve('hyo');
    reject(new Error('not found'))
  }, 1000)
})
// Promise 함수는 선언만 해도 바로 실행됨 -> 만약 버튼을 눌렀을때 
// 실행시키고 싶을땐 주의해서 사용해야함!
// 아래 A 함수는 실행안됨.
const A = () => {
  console.log('hi')
}

// 2. Consumers

promise.then((value) => {
  console.log(value); // .붙여가며 체이닝가능
}).catch((err) => { // 실패했을때
  console.log(err); 
})
.finally(() => {  // 요즘 나온 함수인데 finally를 쓰면 성공하든 실패하든 마지막에 호출됨!
  console.log('finally') 
})

// 3. Promise chaining

const fetchNumber = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
    reject('not found')
  }, 1000)
});

fetchNumber.then(num => num * 2)
.then(num => num + 5)
.then(num => {
  return new Promise((resolve, reject) => { // 또 다른 비동기인 Promise를 써도되는구나!
    setTimeout(() => {
      resolve(num - 2);
    }, 1000)
  }).then(num => num + 5)
})
.then((num) => {
  console.log(num + 10);
}) // 계속해서 체이닝 가능!


// 4. Error Handling

const getBaby = () => 
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Baby') 
    }, 1000)
  })
const getChild = (baby) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // resolve(baby + ' => Child')
      reject(new Error(baby + ' => Child'));
    }, 1000)
  })
}
const getAdult = (child) => 
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(child + ' => Adult');
    }, 1000)
  })

getBaby()
.then(baby => getChild(baby)) // 콜백함수 안에서 인자가 그대로 다른 함수의 인자로 들어갈때 간결하게 쓸수 있음 -> then(getChild)
.catch(err => {
  return 'baby2';
})
.then(child => getAdult(child)) // then(getAdult)
.then(v => console.log(v)) // then(console.log)
.catch()

아까 쓴 callback체이닝을 Promise로 바꿔보기!

class UserStorage {
  loginUser(id, password){
    return new Promise((resolve, reject) => {
      setTimeout(() => {
      if(
        (id === 'hyo' && password === '0416') || 
        (id === 'woo' && password === '0715')
        ){
        resolve(id)
      }
      else {
        reject(new Error('not found'))
      }
    }, 5000)
    }) 
  }

  getRoles(user){
    return new Promise((resolve, reject) => {
      setTimeout(() => {
      if(user === 'hyo'){
        resolve({name: 'hyo', role: 'admin'});
      }
      else {
        reject(new Error('no access'));
      }
    }, 1000);
    })  
  }
}
// 
const userLogin = new UserStorage();
const id = prompt('id를 입력하시오');
const password = prompt('password를 입력하라');

userLogin.loginUser(id, password)
.then(userLogin.getRoles)
.then(v => console.log(v.name + '님 반가워요!'));

async await

// -------------- Async - Await --------------

// async await는 promise를 조금 더 간결하고 그리고 동기적으로
// 실행되는것 처럼 보이게 만들어주는 녀석이다!
// promise 에서 .then().then().then ... 이런 난잡한 promise 위에
// 조금 더 간편한 async await API 를 사용하면 
// 우리가 동기식으로 순서대로 작성하는 것처럼 간편하게 작성할 수 있게 도와준다.


// 1. async

// function fetUser() {
//   return new Promise((resolve,reject) => {
//     resolve('hi')
//   })
// }

// 위의 promise처럼 써도되지만 아래의 async 를 넣고 promise를 쓰지않아도
// 결과값은 Promise {fulfilled 상태!}
// async 라는 키워드를 쓰면 자동으로 코드블럭이 Promise 로 바뀜!

async function fetUser() {
  return 'hi';
}

const user = fetUser();
console.log(user);

// 2. await
// await이라는 키워드는 async가 붙은 함수 안에서만 쓸수 있다.

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve,ms));
}

async function getHi() {
  await delay(3000); // delay(3000)이 끝날때까지 기다려!
  return 'Hi' // 위의 await 키워드 함수가 끝나면 리턴!
}
// 위 async함수를 promise 함수로 만들어 보면 ->
function getHiPro() {
  return delay(3000)
  .then(() => 'Hi2')
}

async function getBye() {
  await delay(3000);
  return 'Bye';
}

// then 지옥!! 으로 써본다.
function concatWords() {
  return getHi()
  .then(h => {
    return getBye().then(b => `${h} && ${b}`)
  })
}

concatWords().then(console.log)

// 위의 then지옥 말고 async 키워드를 써서 간결하고 동기적으로 보이는것 처럼 만들어본다.

async function concatWords2() {
  const hi = await getHi(); 
  const bye = await getBye();
  return hi + bye;
  
}

concatWords2().then(console.log)

// 하지만 위에서 getHi()에서 3초기다렸다가 또 getBye()에서 3초기다리고
// return hi + bye를 실행하는건 비효율적이다
// getHi()와 getBye()는 서로 기다릴필요가없으므로
// 더럽게 쓰지만 한번 써본다.

async function concatWords3() {
  const hiPromise = getHi(); // 기다릴필요없이 getHi()를 실행시킨값을 hiPromise에 할당
  const byePromise = getBye(); // 기다릴필요없이 ~~
  const hi = await hiPromise; // hiPromise를 받아올때까지 기다려!
  const bye = await byePromise; // byePromise를 받아올때까지 기다려!

  return `${hi} ${bye} ~~`
}

concatWords3().then(console.log) 

// 하지만 위처럼 더럽게 쓰지않는다!
// 유용한 Promise APIs 가 있다!
// Promise.all()

function concatWords4() {
  return Promise.all([getHi(), getBye()]) // 모든 Promise들이 병렬적으로 다 받을때까지 모아주는 녀석이다!
  .then(v => v.join(' + ')) // 위의 애들이 다 받아지면 다 받아진 배열이 다시 전달이된다! ['hi','bye']로! 
}

concatWords4().then(console.log)


// 만약 가장 먼저 처음으로 받아오는 데이터만 출력 하고 싶을때 쓰는
// Promise API 를 알아보자!
// Promise.race()

function concatWords5() {
  return Promise.race([getHi(),getBye()]) // 얘는 Promise.all() 처럼 배열의 형태로 받아오지 않아 join안써도되기도하고 쓸수가 없다고 뜬다!
}

concatWords5().then(console.log)
profile
개발 재밌다

0개의 댓글