동기와 비동기란?
1.동기적(synchrounus)
- 순차적으로 진행됨(하나의 작업이 끝나야, 그다음 작업을 진행함)
- blocking(하나의 작업이 끝날 때까지,이어지는 작업을 "막는 것")
2.비 동기적(Asynchronous)
- 순차적으로 진행되지 않음(무거운 작업일경우 빼놓고,그다음 작업으로 넘어감)
- non-blocking(어떤 작업이 끝나지 않아도, 그다음 작업으로 넘어가는 것을 막지않음)
<비동기의 주요 사례>- DOM Elemennt의 이벤트 핸들러
- 마우스,키보드 입력(click,keydown 등)
- 페이지 로딩(DOMContentLoaded 등)
- 타이머
- 타이머 API(setTimeout등)
- 애니메이션 API(requestAnimationFrame)
- 서버에 자원 요청 및 응답
- fetch API
- AJAX(XHR)
비동기적 실행이유와 작동원리
`1. 이유
- 자바스크립트는 기본적으로 싱글쓰레드 방식으로 동작하기 때문에 한 번에 한 가지 일만 수행할 수 있다
- 현재의 웹은 너무나도 커지고 복잡해졌기 때문에 사용자의 동시 다발적인 요청에 빠르게 응답하기 위하여 비동기적 프로그래밍이 불가피해졌다.
- callback 또는 promise ,async awit를 이용해 구현할 수 있다
2.작동원리(이벤트 루프)
- 비 동기로 동작하는 핵심요소는 자바스크립트 언어가 아니라 브라우저가 가지고 있다.(Node에서는 libuv 라이브러리 등)
- 브라우저는 Web APIs, Callback Queue, Event Loop 등으로 구성된다
- 자바스크립트의 힙에는 메모리가 할당 되며(객체), call stack은 실행된 코드의 환경을 저장하는 자료구조이고 함수 호출치 call stack에 push된다
setTimeout(function exec() { console.log('second') }, 1000);
- 위 코드 실행시 setTimeout이 call stack에 들어와 실행되면 Browser API인 timer를 호출한후 call stack에서 제거된다 스케줄링한 시간이 지나면 callback queue에 추가되고 call stack이 모두 호출되어 비어있을 때 call stack으로 이동시킨다
3.정리
- 사용자의 동시 다발적인 요청에 빠르게 응답하기 위하여 비동기적 프로그래밍이 필요하다
- call back과 promise , async awit 를 이용해 비동기적으로 코드를 구현 할수있다
콜백으로만 코드작성하기 =>콜백지옥
const f1 =(callback)=>{ setTimeout(()=>{ console.log("1번주문 완료"); callback() },1000) } const f2= (callback)=>{ setTimeout(()=>{ console.log("2번주문 완료"); callback(); },3000); } const f3= (callback)=>{ setTimeout(()=>{ console.log("3번주문완료"); callback(); },2000) } //콜백지옥의 예시 <= 좋지못함 console.log("시작") f1(()=>{ f2(()=>{ f3(()=>{ console.log('끝') }) }) })
promise 사용방법
//producer code const pr = new Promise((resolve,reject)=>{ setTimeuute(()=>{ resolve('ok') //reject(new Error('err...')) },1000) }); //consumer code pr .then(result=>{console.log(result)})//성공시(resolve()호출)에 실행됨 .catch(error=>{console.log(error)})// 실패시(reject()호출)에 실행됨 .finally(()=>{console.log('end')})//무조건 출력됨
callback hell promise로 바꾸기
//producer code const f1 =() =>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve("1번주문완료") },1000) }); }; const f2 = (message) =>{ console.log(message); return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve("2번주문완료") },3000) }) } const f3 =(message) =>{ console.log(message); return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve("3번주문완료") },2000) }) } //resolve()는 리턴이든 함수본문내에서든 호출만 되면된다 //Consumer code //promises chaining f1() .then(result =>f2(result)) .then(result =>f3(result)) .then(result =>console.log(result)) .catch(error =>console.log(error)) .finally(()=>console.log("end")) //then의 인수에는 함수의 호출이아닌 함수자체를 전달해야한다 //then안의 함수의 인자는 resolve의 인자로 넘어온다 //만약 중간에 실패하면 중간 then을 넘어서 바로 cathch로간다 //finally는 실패하든 성공하든 실행된다 ////전달되는 인자가 하나일때는 생략방법이있다 f1() .then(f2) .then(f3) .then(console.log) .catch(console.log) .finally(()=>console.log("end"))
프러미스 체이닝(promise chaining )
const fetchNumber =new Promise((reslove,reject)=>{ setTimeout(()=>reslove(1),1000); }); fetchNumber .then(num => num*2) .then(num=> num*3) .then(num=>{ return new Promise((resolve,reject)=>{ setTimeout(()=>resolve(num-1),2000); }); }) .then(num=>console.log(num)) //then에서 값을 다른 then으로 전달할때는 전달받은 인자를 함수에서 return시켜야한다 //promise.then은 promise를 리턴한다 //promise.then에서 새로운 프러미스를 전달해도된다
promise all
const f1 =() =>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve("1번주문완료") },1000) }); }; const f2 = () =>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve("2번주문완료") },3000) }) } const f3 =() =>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve("3번주문완료") },2000) }) } Promise.all([f1(),f2(),f3()]) .then((reslove)=>{console.log(reslove)}) //all의 인수로 배열을받는다 //all안의 작업들이 모두 끝이나면 결과를 담은 배열을 리턴한다 //모든작업이 동시에 진행되고, 모두 성공되어야만 결과를 리턴한다. //하나라도 누락되면 안되는경우 사용하기 좋다
promise.race
const f1 =() =>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve("1번주문완료") },1000) }); }; const f2 = () =>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve("2번주문완료") },3000) }) } const f3 =() =>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve("3번주문완료") },2000) }) } Promise.race([f1(),f2(),f3()]) .then(console.log) //가장 빠르게 끝난 작업하나만 리턴한다
async & awit 사용방법
async function getName1() { return 'Mike'; } //async를 함수앞에 붙이면 이 함수는 프러미스를 반환한다 //state는 fulfilled가되고 result는 "Mike"가 된다 async function getName2() { return Promise.resolve("Tom") } //state는 fulfilled가되고 result는 "Tom"이 된다 //앞에 async를 안붙여도 되더라 어느게 보편적이지? // return Promise.resolve("Tom") vs (차이점이뭐지?) //return new promise((resolve,reject)=>{resolve("Tom")}) async function getName3() { throw new Error('err') } getName3() .catch(err=>{console.log(err)}) //throw,try,catch공부
function getName(name){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(name) },1000) }) } async function showName(){ const result =await getName("Mike") console.log(result) } showName(); //1초후 "Mike"가 콘솔에 찍힘 //await키워드는 async함수 내부에서만 사용할 수 있다 //await키워드는 오른쪽으넨 promis가 오고 그 프로미스가 처리될때까지 기다린다
async, await로 콜백지옥 바꿔보기
const f1 =() =>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve("1번주문완료") },1000) }); }; const f2 = (message) =>{ console.log(message); return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve("2번주문완료") },3000) }) } const f3 =(message) =>{ console.log(message); return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve("3번주문완료") },2000) }) } //resolve()는 리턴이든 함수본문내에서든 호출만 되면된다 async function order(){ const result1 =await f1(); const result2 =await f2(result1); const result3= await f3(result2) console.log(result3); console.log("종료") } //만약 reject가 호출되는경우 //async function order(){ // try{ // const result1 =await f1(); // const result2 =await f2(result1); // const result3= await f3(result2) // console.log(result3); // }catch(e){ // console.log(e) // } // console.log("종료") //} order();
- 비동기적으로 실행되는 코드내부에서 마치 동기적인 실행처럼 볼 수 있어 가독성이 매우좋음
질문에 답해보기
- Promise 실행 함수가 가지고 있는 두 개의 파라미터 resolve 와 reject 는 각각 무엇을 의미하나요?
- 성공시 resolve 실패시 reject를 이용해 값을 전달
- resolve, reject함수에는 인자를 넘길 수 있습니다. 이때 넘기는 인자는 어떻게 사용할 수 있나요?
- resolve,reject의 인자에 값을 넣으면 then이나 cahtch 로 받을 수 있다
- new Promise()를 통해 생성한 Promise 인스턴스에는 어떤 메서드가 존재하나요? 각각은 어떤 용도인가요?
- then,cahtch,finally등 컨슈머 코드에 사용된다
- Promise.prototype.then 메서드는 무엇을 리턴하나요?
- promise를 리턴하고 then 인자안의 함수에서 리턴된 값이 프러미스의 vlaue가 된다 상태는 fulfiled
- Promise.prototype.catch 메서드는 무엇을 리턴하나요?
- 프러미스를 리턴하고 상태는 rejected/ catch로 전달받을 수 있다
- Promise의 세 가지 상태는 각각 무엇이며, 어떤 의미를 가지나요?
- pending 대기상태 ,fulfiled 이행된 상태 ,rejected 거부실패된 상태
- await 키워드 다음에 등장하는 함수 실행은 어떤 타입을 리턴할 경우에만 의미가 있나요?
- 프러미스를 리턴하는 경우에만 의미가 있다
- await 키워드를 사용할 경우, 어떤 값이 리턴되나요?
프러미스가 리턴된다- Promise.all 의 인자는 어떠한 형태인가요?
- 배열이다
- Promise.all 을 사용할 경우에 then 메서드의 파라미터는 어떠한 형태인가요?
- 함수다
- Promise.all 에 두 개의 Promise 요청이 전달되고, 만일 그중 하나가 rejected 상태가 되는 경우, then 메서드를 따라가나요, 아니면 catch 메서드를 따라가나요?
- catch