박철순
Javascript 비동기란? 본문
한 번 비동기는 영원한 비동기이다. (비동기를 동기로 바꾸지 말아야 함)
비동기는 동시의 문제가 아니라, 순서의 문제다.
이벤트루프는 호출스택이 비어있으면은 테스크 큐에 있는값을 호출스택으로 실행해줌.
백그라운드,(매크로,마이크로 테스크 큐)로 구성되어있음. 사실 더 많치만 사용하는데는 크게 지장없음.
백그라운드는 다른 언어로 이루어져 있을 수 있어, 동시에 여러개 코드를 실행 할 수 있다.
여기에 들어가는 코드들은 비동기코드들 이 들어감, Js는 ( setTimeout,setInterval,Promise,네트워크요청(ajax),EventListener ) Node.js는 ( Process.nextTick() )
setImmediate() 즉시 실행 함수도 있음.
마이크로 테스크 큐에는 Promise,process.nextTick()만 들어감. (Promise는 resolve,reject가 될 때 테스크 큐로 이동함)
매크로 테스크 큐에는 마이크로에 안들어가는 나머지 비동기코드들이 들어감. (이벤트리스너가 실행 될 때, 선언한 시간이 만족 할 때 백그라운드에서 테스크 큐로 이동함)
백그라운드에서 동시에 테스크 큐로 넘어 갈 경우 '마이크로 테스크 큐'가 먼저 호출스택으로 들어감. ( Promise는 resolve,reject 함수가 호출 될 때, 백그라운드에서 테스크 큐로 이동함)
비동기 동작 방법 -
'백그라운드'에 있는 값들이 '매크로 테스크 큐'로 이동을 한 후 들어온 순서대로 호출스택이 비어있으면은 이벤트루프를 통해 호출이 됨. (First In First Out)
Promise란, 실행은 바로 하되, 결과값을 나중에 원할 때 쓸 수 있는 것.
new Promise((resolve,reject)=>{ (resolve는 return값이랑 같음, then을 통해 호출이 됨.), (reject는 에러(예외처리)가 발생하면 catch로 호출이 가능.) })
그리고, Promise의 콜백함수는 동기함수이면서 바로 호출함. 왜냐하면 나중에 then을 통해 호출 할 때, 값을 가지고 있어야 하기 때문.(추측)
then,catch 는 바로 실행이 안되고, Promise의 호출스택이 다 비워진 다음에야 호출스택으로 올라감.
하지만, 결과값을 바로 사용하고 싶을 때는 결과값이 나오면은 값을 기다린 후 바로 실행 됨.
setInterval은 주기적으로 실행이 되기 때문에, clearInterval이 실행 되기 전까지, 백그라운드에서 존재하다가 선언시간이 지나면은, 마이크로 데스크 큐로 이동 후 호출스택이 비워질 때 올라감.
Promise에 resolve를 값을 안주고 호출을 하면은, then에 매게변수값에는 아무값이 안들어가지만, 콜백함수는 실행이 됨.
then을 체인을 하여 여러개를 만들었을때, 중간에 에러가 나면은 catch가 실행 됨. 여러개면은 앞의 then이 에러가 나면은 가장 가까운 catch에서 오류가 실행 됨.
체인의 retrun값, Promise.resolve(값) 은 다음 then의 매개변수(result)값으로 들어감. 만약 return값을 안넣어줬으면은 undefined다.
이 부분은 await도 똑같다. const a = await 1; const b = await Promise.resolve(1);
async의 함수는 await이 만나는 순간 동기부분이 끝남. 그리고, async 함수의 retunr값은 then의 매개변수값이다.
비동기함수를 위에 두고 밑에 다른값을 사용하면 Promise는 먼저 실행이 되지만, async는 밑에 값이 실행 된 후 호출값이 실행이 됨.
추측상, Promise는 변수에 할당하면서 자연스럽게 호출이 되지만, async 함수는 실행했을 때 호출이 됨.
Promise는 resolve나 reject 만나기 전이 동기, async 함수는 await 만나기전까지 동기.
동시에 결과값을 얻고 싶을 때는, Promise는 실행을 하되 Promise.all([arg1,arg2])을 통해 동시에 원할 때 사용이 가능.
await을 연달아 쓰는 값이면은, 서로 비교해서 동시에 사용이 가능한지 구분하고 Promise.all(), Promise.allSettled()를 사용하면 됨.
그리고, Promise는 .then/await를 안붙혀도 바로 실행이 됨.
async에서 Promise로 바꾸기위해서는 (근데 굳이 안바꿔도 됨) -
1. await이 기준으로, then을 붙여주면됨.
1-2. 처음 나오는 await이 Promise면은 처음값으로 넣은 상태로 시작해도 됨. 아닌값은 Promise.reslove().then(()=>{}); 이런식으로 해야함.
2. await 과 await의 사이값은 이전의 then의 콜백함수에 넣어주면 됨. 그리고 다음 await값은 return으로 넣어주면 됨.
3. await값 마지막에 return값이 있으면은 Promise 마지막 then값에 return을 넣어주면 됨.
4. Promise와 async는 1:1 대응이 아니지만, 만약, async의 스코프체인과 같이 await값을 써야하면은, Promise는 리턴값에 계속 넣어주면서 필요한값을 다음 then값에 넘겨줘야 함.
async함수안에 return값에 값을 쓰든, Promise.reslove()을 통해 then값이 사용이 가능.
async함수안에서 await를 사용하면 프로미스 처리될 때까지 기다리다가, 그 이후 결과값 반환.
try..catch로 에러 핸들링이 가능하나, async함수 밖에서는 await를 사용 할 수가 없어서, .then/catch로 최종결과나 에러를 처리합니다.
여러 작업이 있고, 이 작업들이 모두 완료될 때까지 기다리려면 Promise.all을 활용할 수 있다는 점도 알고 계시기 바랍니다
async 함수는 언제나 프라미스를 반환합니다.
자바스크립트에서는 non-blocking이 async이다.
Babel에서 async 함수는 제너레이터(generator)로 바꿈
프로미스는
실행은 바로 --> 결과값은 나중 --> 결과값을 사용할때는 더 나중
실행은 바로 --> 결과값도 거의 바로 사용 --> 그 다음에 결과값 나오면 --> then,await,Promise.all 이런게 결과값을 기다린 후에 실행.
await과 .then은 거의 똑같다고 보면 됨.
백그라운드 역활이 브라우저도 있음. 그래서 동시에 많은양의 네트워크를 보내면은, 동시에 보낼 수 있는 양이 정해져있어서, 순서대로 보내게 됨.
map같은 반복문에서는 Promise의 순서가 보장 안됨. (동시에 실행 됨)
그렇치만 for (let result of results) { await result } 순서 보장 됨. (순서대로 실행 됨)
Array.map()의 콜백함수로 비동기함수를 사용하면은 순서를 보장 못 받음.
.map() 자체는 약속에 대응하지 않으므로 루프의 각 반복이 해결될 때까지 "대기"하지 않습니다.
따라서 결과 async로 약속을 반환하는 N 함수를 호출한 결과가 .map()있습니다. 이것이 코드가 작동하는 방식입니다.
반복문을 for 루프(약속 인식)를 바꾸든지, Promise.all로 해결 해야함.
An array of promises is returned when using axios in map function?
I am mapping through this dummyAssests array and want to create a new array of objects based on the axios response called newAssetArray. But when I console.log the newAssetArray it just contains an...
stackoverflow.com
https://www.youtube.com/watch?v=A7AeQzEoEmc&t=3939s
'Javascript' 카테고리의 다른 글
Math.max() (0) | 2022.04.21 |
---|---|
Math.pow(), Math.sqrt() (0) | 2022.04.09 |
Javascript Prototype (0) | 2022.04.06 |
Javascript Event (0) | 2022.04.06 |