Asynchronous_엘리님 강의 정리

=================================<< 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');

//Synchronous callback
function printImmediately(print){ // 호이스팅이 되서 코드 젤 상단으로 올라가지만
    print();
}
printImmediately(()=>console.log('hello'));// 여기서 불렀으니 여기서 실행됨

//Asychronous callback
function printWithDelay(print, timeout){//setTimeout을 감싸고 있는 함수, 전달받은 인자를 set~에게 전달
    setTimeout(print, timeout);
}

printWithDelay(()=> console.log('async callback'), 2000);//콜백함수와 2초를 전달하자


//Callback Hell example
class UserStorage {
  loginUser(id, password, onSuccess, onError){
      setTimeout(()=>{
          if(
            (id === 'nara' && password === 'artist') ||
            (id === 'enda' && password === 'dreamer')  
          ){
            onSuccess(id); //전달받은 onSuccess 라는 콜백을 불러서 id를 전달해준다
          }else{
            onError(new Error('not found')); // 만약 발견되지 않았으면 onError 콜백을 불러서 Error 오브젝트 만들어서 'not found' 전달해줄거다
          } 
       }, 2000);// 이 코드블럭을 2초뒤에 실행해줘~ 라는 의미,
     }

  getRoles(user, onSuccess, onError) {
      setTimeout(()=> {
          if(user === 'nara'){
              onSuccess({name: 'nara', role: 'genius'});// 객체 전달
          } else {
              onError(new Error('no access'));
          }
      }, 1000)
  }

}

// 1. 사용자에게 id, password 입력 받아온다
// 2. 서버에게 로그인
// 3. 로그인한 사용자에게 id받아오고, 다시 roles 요청해 받아온다 :mean 만든 인스턴스의 gerRoles에 다시 접근(인자전달) 밑 참고
// 4. 사용자의 오브젝트를 얻게됨(걔네를 출력) 

const iamUser = new UserStorage();
const id = prompt('enter your id');
const password = prompt('ente your password'); // prompt를 변수로 저장해 밑에 인자로 넣어줌으로써 사용자가 입력하는 값을 전달하게끔

iamUser.loginUser(
   id, 
   password, 
   user => {
     iamUser.getRoles(
       user,
       obj => { 
        alert(`Hello ${obj.name}, ${obj.role}`)
       },
        error => {
          console.log(error)
        }
       );
   },
   error => {
     console.log(error)
   }
); 


//콜백지옥 : 가독성 떨어짐/ 에러발생, 디버깅시 어려움/ 유지보수 어려움
==================================<< Promise >>===================================

// Promise is a JavaScript object for asynchronous operation.
// # State: pending -> fulfilled / rejected  (기능을 수행하고 있는 중인지, 성공했는지, 실패했는지)
// # Producer vs Consumer (데이터 제공자와 데이터 소비자)

//promise 안에서 (resolve or seject 호출 안하면 pending 상태됨)

// 1.Producer
// executer의  콜백함수를 만든다-> promise 만드는 순간 executer 콜백함수가 바로 실행됨
const promise = new Promise((resolve,reject) => {
  //doing some heavy work(network, read files)  ->  network, read files 들이 promise 만드는 순간 실행됨 -> but 순서를 정해주고 싶을땐?
  //  시간이 걸리는 것들은 비동기적으로 처리하는 것이 좋다.
  console.log('doing something...');
  setTimeout(()=>{
     resolve('nara');     // 성공적으로 받아온 데이터를 resolve라는 콜백함수 통해 전달
     reject(new Error('no network'));   // Error class: one of JavaScript object
  }, 2000);

}) 

// 2. Consumers: then, catch, finally
promise
   .then(value => {
     console.log(value);   // When you invoke 'then', -> return the same Promise, so 'catch' can use it
   })
   .catch(error =>{
     console.log(error);
   })
   .finally(()=>{
     console.log('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 => {          // # then: 값 바로 전달, 혹은 또 다른 비동기 promise 전달
    return new Promise((resolve, reject)=>{         //다른 서버에 보내서 다른 숫자로 변환된 값 받아올거다-> 새로운 promise 리턴
      setTimeout(()=> resolve(num-1), 1000);
    })
  })
  .then(num => console.log(num));
   
// 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); // resolve(`${hen}=> 🥚`)
  });

const cook = egg => 
  new Promise((resolve, reject)=> {
   setTimeout(() => resolve(`${egg} => 🍳`), 1000);
  }); 

getHen()
 .then(hen => getEgg(hen)) // 값 받아서 인자로 넘겨줌 
 //.catch(error =>{return '🥖'}) // 계란을 받아오는데 문제가 있어도 전체 promise 체인에 문제가 생기지 않도록 (cook에 빵전달)
 //.catch(console.log)  //   Error: error! 🐔=> 🥚 at promise.js:55 // undefined => 🍳  at promise.js:67
 .then(egg => cook(egg)) 
 //.catch(console.log) ->여기서 잡으면 에러메세지+ 밑 undefined 됨. 아무것도 넘겨주지 않아서?
 .then(meal => console.log(meal))
 .catch(console.log) // 에러가 밑으로 전달되서 잡혀짐 Error: error! 🐔=> 🥚 at promise.js:55



//  .then(getEgg)  콜백함수를 전달할때 받아오는 value를 바로 다음함수에 전달시 생략 가능
//  .then(cook) 
//  .then(console.log);
===============================<< Callback to Promise >>================================
  class UserStorage {
    loginUser(id, password){
        return new Promise ((resolve, reject)=>{
            setTimeout(()=>{
              if(
                (id === 'nara' && password === 'artist') ||
                (id === 'enda' && password === 'dreamer')  
              ){
                 resolve(id); 
              }else {
                 reject(new Error('not found'));
              }      
            }, 2000)
        }) 
    } 
    getRoles(user){
        return new Promise ((resolve, reject)=>{
            setTimeout(()=> {
              if(user === 'nara'){
                  resolve({name: 'nara', role: 'genius'});
              } else {
                  reject(new Error('no access'));
              } 
            }, 1000)
          
        })
      }

}

  const iamUser = new UserStorage();
  const id = prompt('enter your id');
  const password = prompt('ente your password'); 

  iamUser.loginUser(id,password)
   .then(iamUser.getRoles)
//    .then(id => 
//      iamUser.getRoles(id) // 전달하는 인자와 받는 인자가 같으면 생략가능
    .then(obj =>  alert( `Hello ${obj.name}, ${obj.role}`))
   .catch(console.log);
==================================<< Async >>===================================
  // async & await
// clear sytle of using  promise :)


// function fetchUser() {
//     return new Promise((resolve, reject)=>{
//         //do network request in 10 secs...
//         resolve('nara');
//     });
// }

//########### fetchUser().then(data=> console.log(data)); // 함수로 바로 호출하는 방법
//############ 밑은 변수에 할당해서 호출
// const user = fetchUser();      // fetchUser 라는 것은 결국 promise 리턴, then 콜백함수 이용 유저가 들어오면 console.log출력
// user.then(console.log);  // nara
// console.log(user);     // Promise {<fulfilled>: "nara"}
//-------------------------------------------
// Promise {<fulfilled>: "nara"}
// __proto__: Promise
// [[PromiseState]]: "fulfilled"
// [[PromiseResult]]: "nara"

// 1. async
async function fetchUser() {
  //do network request in 10 secs...
   return 'nara';
    
}

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


// 2. await
// 동기적인 코드 쓰는 것처럼 보임 , 가독성이 좋다

function delay(ms) {
    return new Promise (resolve => setTimeout(resolve, ms)) // 정해진 ms가 지나면 resolve 호출
}

async function getApple(){   // 'await' can be used in the function which has 'async' keyword
  await delay(1000);     // 'await' waits until the delay function finished(?) for 3 seconds, 
  return '🍎';     //  and then makes 'Promise' as it has 'async' keyword, returning apple.
}

async function getBanana(){
  await delay(2000);
  //throw new Error(`error`);
  return '🍌';
}

//###################################### 굳이 프로미스를 쓰는 함수를 만들어보면 ##################################
// function getBanana (){  
//   return delay(3000) // 바나나 안에서 프로미스 리턴
//   .then(()=> '🍌')  // 어떤 값을 받던지 결국엔 바나나 리턴하는 함수 만듬
// }

// function pickFruits(){
//   return getApple().then(apple => {
//     return getBanana().then(banana => `${apple} + ${banana}`); // 받은 인자들을 출력하기 위해..``template? 씀 
//   })
// }

//############################################### await 사용 ###################################################
// async function pickFruits(){
//     const apple = await getApple(); // 저 두 await한 함수들은 서로 연관성 x -> 순차적으로 진행하면 비효율적
//     const banana = await getBanana();
//  
//     return `${apple} + ${banana}`;
// }

//########################################### await - error 처리 #################################################
// async function pickFruits(){
//     let apple = null;
//     try {
//        apple = await getApple(); 
//     } catch (error) {
//        console.log(error);
//     }
//     let banana = null;
//     try {
//         banana = await getBanana();
//     } catch (error) {
//       console.log(error);
//     }     
//     return `${apple} + ${banana}`;
//  }



async function pickFruits(){ //  위 두 await한 함수들은 서로 연관성 x -> 순차적으로 진행하면 비효율적
     const applePromise = getApple();  // promise는 만드는 순간 코드 블럭 실행됨-> 사과와 바나나에 promise 만들어서 병렬적으로 코드 수행됨
     const bananaPromise = getBanana();  // 둘다 delay promise에서 값을 받아오니까.. 이렇게 함수를 promise로 저장가능??
     const apple = await applePromise; 
     const banana = await bananaPromise;
   return `${apple} + ${banana}`;
 }

pickFruits().then(console.log);

// 3. useful APIs
//모든 promise들을 다 받을때까지 병렬적으로 묶어줌-> 배열형태로 전달하면, 그 배열이 전달되고..

function pickAllFruits(){
  return Promise.all([getApple(),getBanana()]).then(fruits => 
    fruits.join(' + ')
  );
}

pickAllFruits().then(console.log);

//배열에 전달하는 promise중 가장 먼저 값 리턴하는 아이만 전달되어짐

function pickOnlyOne() {
  return Promise.race([getApple(),getBanana()]);
}

pickOnlyOne().then(console.log);
 

좋은 웹페이지 즐겨찾기