[JS] Aysnc / Await / Job Queue(Micro Queue)

colki·2021년 5월 10일
0
post-custom-banner

Udemy_JavaScript: The Advanced JavaScript Concepts (2021) 강의를 바탕으로 메모한 내용입니다.

async

async 키워드를 함수 앞에 붙여주면 코드블럭이 promise로 바뀐다.

자바스크립트에게 야 이거 비동기함수임! 이라고 알려주는 것.

An async function is a function that returns a promise.
promise를 리턴하는 함수로 만들어 준다.


example 01

/*  Promise  */
function fetchUser() {
  return new Promise((resolve, reject) => {
    resolve('hi');
});
}

var user = fetchUser();

console.log(user); // hi

/*  Async  */ 
async function fetchUser() {
  // resolve 값을 리턴하는 코드 한줄로 대체. 깔-끔!
  return 'hi'; 
}

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

Promises have this done then that you keep having to change

Async on the other hand has this async word in front of it and some await keywords.

example 02

/*  Promise  */
movePlayer(100, 'Left')
  .then(() => movePlayer(400, 'Left'))
  .then(() => movePlayer(10, 'Right'))
  .then(() => movePlayer(300, 'Left'))
  
/*  Async  */ 
async function playerStart() {
  const firstMove = await movePlayer(100, 'Left');
  await movePlayer(400, 'Left');
  await movePlayer(10, 'Right');
  await movePlayer(300, 'Left');
}

await

async 가 붙은 함수 안에서만 사용할 수 있다.

Promise가 resolve되거나 reject될 때까지 async 다음의 함수실행을 정지하고 기다렸다가 promise의 resolve 값 을 받아서 리턴한다.
리턴값을 변수에 담을 수 있다!

reject일 경우에는 에러를 던진다!

리턴값이 담겨있는 async함수를 실행하면 동작하게 비동기함수가 동작하게 된다!
(위에서처럼 return ; 이 없고 awaite이 return 을 품고 있는 형태)

끝날 때까지 기다려준 뒤 동작하기 때문에 동기적으로 해석되기도 한다.


example 01

function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

⏬
  
async function f1() {
  var x = await resolveAfter2Seconds(10);
  // return문은 없음!
  console.log(x); // 10
}

f1();

example 02

async function playerStart() {
  const first = await movePlayer(100, 'Left');
  const second = await movePlayer(400, 'Left');
  const third = await movePlayer(10, 'Right');
  const fourth = await movePlayer(300, 'Left');
}

async/await vs Promise

💡 async, await은 promise의 대체재가 아닌 선택에 따라 사용하는 것이다.

promise나 async나 .then을 이용해서 resolve, reject등을 받는 건 같으나 명시적으로 프로미스를 사용해서 return promise~ 하느냐
async function~해서 리턴값을 resolve/then 인자로 쓰느냐~ 차이


example 01

JSON Placeholder에서 콘솔열고 테스트하면 reject없이 fetch된다!

/*  Promise  */
fetch('https://jsonplaceholder.typicode.com/users')
  .then(resp => resp.json())
  .then(console.log)

//  (10)[{...}, ... , {...}]


/*  async/await  */
async function fetchUser() {
  const resp = await fetch('https://jsonplaceholder.typicode.com/users')
  const data = await resp.json()
  console.log(data);
}

fetchUser();
//  (10)[{...}, ... , {...}]

example 02

const urls = [
  'https://jsonplaceholder.typicode.com/users', // 10
  'https://jsonplaceholder.typicode.com/posts', // 100
  'https://jsonplaceholder.typicode.com/todos' // 200
];

/*  Promise  */
Promise.all(urls.map(url => {
  return fetch(url).then(resp => resp.json())
})).then(results => {
  console.log('users : ', results[0])
  console.log('posts : ', results[1])
  console.log('todos : ', results[2])
})


/*  async/await  */
const getData = async function () {
  const [ users, posts, todos ] =
    await Promise.all(urls.map(url =>
    fetch(url).then(resp => resp.json())
  ))

  console.log('users : ', users);
  console.log('posts : ', posts);
  console.log('todos : ', todos);
}

 
// users : (10) [{...}, ... , {...}]
// posts : (100)[{...}, ... , {...}]
// todos : (200)[{...}, ... , {...}]

async/await_ Error Handling

promise에서는 .catch 메서드로 에러를 잡았다면,

async/await은 자바스크립트에서 기본적으로 에러핸들링할 때 사용하는
try... catch 블록문을 사용해서 에러핸들링을 해주면 된다.


const getData = async function () {

  try {
    const [ users, posts, todos ] =
    await Promise.all(urls.map(url =>
    fetch(url).then(resp => resp.json())
  ))

  console.log('users : ', users);
  console.log('posts : ', posts);
  console.log('todos : ', todos);

  } catch(err) {
    console.log(err 'oops!')
  }
}

for await...of

for await...of feature does it allows us to loop through these multiple promises.

for await (const request of arrayOfPromises) {... 

/* example */
const urls = [
  'https://jsonplaceholder.typicode.com/users', // 10
  'https://jsonplaceholder.typicode.com/posts', // 100
  'https://jsonplaceholder.typicode.com/todos' // 200
];

const getData = async function () {
  const arrayofPromises = urls.map(url => fetch(url));
  // map으로 urls 요소를 fetch 한 새 배열을 생성
  
  for await (const request of arrayofPromises) {
    const data = await request.json(); //await keyword!
    console.log(data);
  }
}

getData();  

Job Queue

Promise는 최근에 ECMA 에 추가된 새로운 것이기 때문에, 이벤트루프도 역시 변경되어야 했다.
기존에 사용하던 Task Queue(Callback Queue)말고도 Job Queue(Microtask Queue)가 추가 되었다.

Task Queue에는 웹 API에 등록된 콜백함수가 들어간 반면에,
Promise가 resolve되면 then에 등록된 콜백함수가 WebAPI 에 등록됐다가 Job Queue로 들어간다.
(Promise를 선언만 하면 안되고 then 콜백함수가 실행되어야 한다)

job queue gets checked first because it has higher priority.

Event Loop는 우선순위가 먼저인 Job Queue에서 콜스택에 넣을 게 있는지 먼저 들여다보고, 없으면 다음으로 Task Queue에 가서 찾아본다.

도중에 promise 일감이 들어오면 그것을 전부 쳐낸다.
그래서 then안에 then 안에 then..이렇게 코드를 작성하면 Event Loop가 계속 머물러 있으므로, 프로세스가 제대로 작동하지 못해서 브라우저는 업데이트 되지 않고 멈춰버릴 수 있다.

💡 Event Loop는 Job Queue에서는 모든 일이 끝나야만 순회하고,
Task Queue에선 일 하나만 하고 바로 또 순회한다!

즉, Job Queue가 텅텅 비워지기 전까지는 Event Loop가 Job Queue에 머물러 있기 때문에 Task Queue에서 CallStack으로 넘어가는 애들은 없다!

Job Queue 일거리를 모두 소화하면 Event Loop가 다시 순회를 재개하고 Task Queue로 넘어간다. 그런데 Task Queue에서 CallStack으로는 한 번에 하나밖에 못 건네 주므로, 하나 보내고 또 Event Loop가 순회한다.

//Callback Queue
setTimeout(() => console.log('태크스큐 1'), 0);
setTimeout(() => console.log('태스크큐 2'), 10);

//Job Queue
Promise.resolve('hi').then(data => console.log('마이크로큐 3', data));

//동기
console.log('4 그냥 동기');

/*  Result  */
// 그냥 동기 4
// 잡큐 3 hi
// undefined 
  => 우선순위인 잡큐까지처리하고 함수끝남
  
// 콜백큐 1
// 콜백큐 2
profile
매일 성장하는 프론트엔드 개발자
post-custom-banner

0개의 댓글