- 동기와 비동기
✔ Javascript is synchronous 동기
-> 호이스팅이 된 이후부터 코드의 순서에 따라 실행
✔ hoisting: var, funciton declaration등이 젤 위로 올라가는 것// asynchronous(비동기) 예시 console.log('1'); setTimeout(() => console.log('2'),1000); // 콜백 함수 console.log('3'); // 1 3 2 // Synchronous callback function printImmediately(print){ print(); } printImmediately(()=>console.log('hello')); // 1 3 hello 2 // Asynchronous callback function printWithDelay(print, timeout){ setTimeout(print,timeout); } printWithDelay(()=>console.log('async callback'),2000); // 1 3 hello 2 async callback
- callback hell example
class UserStorage{ loginUser(id,password,onSuccess,onError){ setTimeout(()=>{ if ((id === "yoon" && password ==="min")|| (id === "angela" && password ==="lucy")){ onSuccess(id); }else{ onError(new Error('not found')); } },2000); } getRoles(user, onSuccess, onError){ setTimeout(()=>{ if (user==="yoon"){ onSuccess({name:"yoon", role: "admin"}); }else{ onError(new Error('no access')); } },1000); } } // 1. 사용자에게 id, pw 입력받아옴 // 2. login // 3. roles // 4. object 출력 const userStorage = new UserStorage(); const id = prompt("enter your id"); const password = prompt("enter your password"); 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)} );
✔ 콜백 체인의 문제점
- 가독성이 떨어진다
- 유지보수가 어렵다
✔ 비동기를 간편하게 처리할 수 있게 해주는 javascript object
✔ 정해진 장시간의 기능을 수행하고 나서 정상적으로 기능이 수행된다면 성공의 메시지와 함께 처리된 결과값을 전달, 문제 발생하면 에러 발생
1. state: pending -> fulfilled or rejected
2. producer vs consumer
- Producer 제공자
// promise를 만드는 순간 콜백함수 내용 바로 실행 // when new Promise is created, the executor runs automatically!!!! const promise = new Promise((resolve, reject)=>{ // doing some heavy work(network, read files) console.log("doing something..."); // doing something... setTimeout(()=>{ resolve("yoon"); // 성공시 reject(new Error("no network")); // 실패시 },2000); });
- Consumer 사용자
// then, catch, finally를 통해 값을 받아옴 // value에는 성공시 yoon이 들어옴 // then: promise가 정상적으로 잘 수행이 되어서 마지막으로 resolve함수를 통해 전달한 값을 value의 pararmeter로 전달 // catch: error 발생시 어떻게 처리할 것인지 // finally: 성공과 실패 여부와 상관없이 마지막에 무조건 호출 promise .then((value)=>{ console.log(value); // yoon }) .catch((error)=>{ console.log(error); // Error: no network }) .finally(()=>{ console.log("finally"); // finally });
- Promise chaining
// then: 값 또는 promise 전달 const fetchNumber = new Promise((resolve, reject)=>{ setTimeout(()=>resolve(1),1000); // 1 전달 }) fetchNumber .then(num=>num*2) // 2 .then(num=>num*3) // 6 .then(num=>{ return new Promise((resolve,reject)=>{ setTimeout(()=>resolve(num-1),1000); // 5 }); }) .then(num=>console.log(num)); // 5, 2초 소모
- 오류 잘 처리 하기
- callback to promise
class UserStorage{ loginUser(id,password){ return new Promise((resolve, reject)=>{ setTimeout(()=>{ if ((id === "yoon" && password ==="min")|| (id === "angela" && password ==="lucy")){ resolve(id); }else{ reject(new Error('not found')); } },2000); }); } getRoles(user){ return new Promise((resolve, reject)=>{ setTimeout(()=>{ if (user==="yoon"){ resolve({name:"yoon", role: "admin"}); }else{ reject(new Error('no access')); } },1000); }); } } const userStorage = new UserStorage(); const id = prompt("enter your id"); const password = prompt("enter your password"); userStorage .loginUser(id,password) .then(userStorage.getRoles) .then(user => alert(`hello ${user.name}, you have a ${user.role} role`)) // 성공했을 경우 .catch(console.log); // 실패했을 경우
✔ syntactic sugar
✔ clear style to using promise
- async
// async를 쓰면 코드 블럭 안이 자동으로 promise로 변경됨 async function fetchUser(){ // do network request in 10secs... resolve("yoon"); } const user = fetchUser(); console.log(user);
- await
✔ async 함수 안에서만 사용 가능function delay(ms){ return new Promise(resolve=>setTimeout(resolve,ms)); } async function getApple(){ await delay(1000); // delay(1초)가 끝날때까지 기다려준다 throw "error"; return "apple"; } async function getBanana(){ await delay(2000); return "banana"; } async function pickFruits(){ // 병렬적으로 실행하기 const applePromise = getApple(); const bananaPromise = getBanana(); const apple = await applePromise; const banana = await bananaPromise; return `${apple} + ${banana}`; } pickFruits().then(console.log); // apple + banana
- useful Promise APIs
// 1. Promise.all // promise에 배열을 전달하게 되면 모든 promise들이 병렬적으로 다 받을 때 까지 모음 function pickAllFruits(){ return Promise.all([getApple(),getBanana()]) .then(fruits=>fruits.join(" + "); } pickAllFruits().then(console.log); // apple + banana // 2. Promise.race // promise에 전달된 배열 중에서 가장 먼저 return된 것 전달 function pickOnlyOne(){ return Promise.race([getApple(),getBanana()]); } pickOnlyOne().then(console.log); // apple