동기 (synchronous) - JS
js는 싱글스레드 작업수행방식
먼저 작성된 코드를 다 실행 후 뒤에 작성된 코드를 실행(블로킹 방식)
한 task마다 시간이 길때 흐름이 늦어지는 문제가 발생
따라서, mulit-thread의 방식으로 여러가지의 thread를 사용해 비동기 작업처럼 보이게 할 수 있음.
Multi-thread 와 비동기는 다른의미인데 나는 아직 잘 모르겠다..
Multi-thread
non-blocking방식으로 여러개의 작업을 동시에 실행하는 방식 (단일 task마다 callback을 수행시킴)
Memory Heap과 Call stack
위의 그림이 JS가 동기와 비동기를 구분하는 법이다(js engine)
function A(){
return 1;
}
function B(){
return A() + 1;
}
function C(){
return B() +1;
}
console.log(C())
이와 같은 코드는 실제 call stack에 Main Context => C() => B() => A()로 실행된다.
그 후 반대로 종료되면서 Context가 종료된 후 callStack이 종료된다.
function async(a,b,cb){
console.log('hi')
setTimeout(() => {
const res2 = a+b;
cb(res2)
},3000)
}
async(1,3, (res) =>{
console.log("res===>" +res)
})
setTimeout비동기를 만들어주는 함수.
cb라는 callback함수를 만들어 3초 뒤에 async()가 실행된다.
비동기함수에는 web Apis, callback Queue를 같이 알아야 하는데,
처음 동기와 프로세스와 같이 Context -> a() -> setTimeout()+cb()을 호출한다.
이때 setTimeout은 cb()를 같이 넣어서 호출 후는 web Apis로 빠진다.
따라서 Web Apis로 가있동안 호출되었던 a()는 종료되고 cb()은 callback Queue로 간다. 그 후 event loop를 따라 Main Context에 남은게 있는지 확인 후 cb()를 실행한다. 아직 완벽하지 않은 개념이다..
Promise
callback함수의 지옥
function a (a, b, cb) {
setTimeout(() => {
const res = a+b;
cb(res)
return res;
}, 1000);
}
console.log("코드 끝")
function b ( a ,cb1){
setTimeout(() =>{
const res1 = a * 2;
cb1(res1)
return res1;
}, 100);
}
function c (a, cb){
setTimeout(() =>{
const res = a * -1;
cb(res)
return res;
}, 3000);
}
a(4,5,(a_res) =>{ // a호출
console.log("a" +a_res);
b(a_res,(b_res)=>{ // b호출 후 매개변수 => a리턴 값
console.log("b"+b_res)
c(b_res,(c_res) =>{ //c호출 후 매개변서 =>b 리턴 값
console.log("c"+ c_res)
});
});
});
와 같이 callback을 겨우 3번 사용했음에도 지옥과 같이 길다.
이것을 해결하기 위해 생긴 것이 Promise다
이처럼 비동기 작업이 가질 수 있는 3가지 상태로 PENDING, RESOLVED, REJECTED가 있다.
Promoise 예시(2가지)
function Promise(number){ const executor = (resolve, reject) => { setTimeout(() =>{ if(typeof number === 'number'){ //숫자인지 판별 //성공 -> resolve resolve(number >= 0 ? '양수': '음수') //삼항 연산자 console.log(number); }else{ //실패 reject("주어진 값이 숫자가 아니다.") } }, 1000) } /* async 선언하면서 promise객체 생성. 실행자 힘수인 executor * const asyncTask = new Promise(executor); return asyncTask; } const res = Promise(10) // number의 타입을 아무거나 입력 res .then((res) => {console.log("reslove==>"+ res)} ) .catch((err) => {console.log("reject ==> "+err)} )
function a(a,b){ /* 이게 const executorA = new Promise(executorA)와 같다. */ return new Promise((resolve,reject) =>{ setTimeout(() =>{ const res = a+b; resolve(res) },1000) }) } function b(a){ return new Promise((resolve,reject) =>{ setTimeout(() =>{ const res = a *2; resolve(res) },2000) } } function c(a){ return new Promise((resolve,reject)=>{ setTimeout(() =>{ const res = a * -1; resolve(res) },3000) }) } //실행부 const ProimseA = a(5,4) //a함수 호출 후 PromiseA라는 상수 선언 .then((a_res) =>{ //then으로 나눌 수 있다. console.log('a'+a_res); return b(a_res); //b함수 반환 }); console.log("테스트테스트") //중간에 console.log를 실행시켜도 상관없음. console.log("테스트테스트") console.log("테스트테스트") //다시 PromiseA 를 받아서 작업. ProimseA.then((b_res)=>{ console.log('b'+ b_res) return c(b_res); //c함수 반환 }) .then((c_res)=>{ console.log('c'+ c_res) })