[JS] 동기 & 비동기

Daily Dev Blog .·2021년 12월 12일
0

JavaScript

목록 보기
3/3
post-thumbnail

JavaScript를 공부하다보면 동기와 비동기의 개념을 알아야하고, 공부하다보면 연결되어 있는 것들이 있다. 개념부터 차근차근 알아가며 나머지 부분들도 정리해보려고 한다.

1. Sync(동기) & Async(비동기) 개념

1) Sync(동기): 정해진 순서에 맞게 직렬적으로 코드를 수행하는 것을 말한다.

2) Async(비동기): 언제 코드가 실행될지 예측할 수 없는, 병럴적으로 코드를 수행하는 것을 말한다.

javaScriptsynchronous한 프로그래밍 언어이다. 즉, *hoisting된 이후부터 코드가 나타나는 순서대로 실행된다는 뜻이다. 이중 비동기적으로 실행되게 보이는 함수가 있는데 Ajax 요청코드, eventListener, setTimeout 등이 있다.

*hositing이란?: var, let 변수 등, function 선언들이 제일 상단으로 올라가는 것이다.

// Sync & Async 예제
//print 라는 callback을 받아서 바로 실행하는 함수
function printImmediately(print) {
  print();
}

function printWithDelay(print, timeout) {
  setTimeout(print, timeout);
}

console.log("1"); // 동기
setTimeout(() => console.log("2"), 1000); // 비동기
console.log("3"); //동기
printImmediately(() => console.log('hello'); // 동기
printWithDelay(() => console.l0g("async callback"), 2000); // 비동기                 

2. CallBack

다른 코드의 인수로서 넘겨주는 실행 가능한 코드를 말한다. 콜백을 넘겨받는 코드는 이 콜백을 필요에 따라 즉시 실행할 수도 있고, 아니면 나중에 실행할 수도 있다.

// callback 예제
setTimeout(() => console.log("2"), 1000); 
//console.log("2") 자리를 callback 함수라고 할 수 있다.
//setTimeout은 *Web Broswer API이다.

3. Promise

javaScript에서 제공하는 비동기를 간편하게 처리할 수 있도록 도와주는 object로, 정해진 기능을 수행하고 나서 정상적으로 수행되었다면 성공의 메세지와 함께 처리된 결과값을 전달해주고, 예상치 못한 문제가 발생했다면 error를 전달해준다.
 새로운 promise가 생성되면 그 executer는 자동으로 실행되기 때문에 network를 연결하는 코드를 내부에 작성할 경우, 이용자가 원치않을 때에도 통신을 하기 때문에 주의해야한다.

promise에는 resolvereject라는 콜백함수를 받는 executer를 만들어서 사용한다. resovereject를 호출하지않고 return하게 되면 promise의 state는 pending이 된다. 그렇기에 항상 resolove나 reject를 이용해 return해주어야 한다. 완료시에는 fulfilled, 실패시에는 rejected.

// Promise 예제
// (1)은 error 핸들링할 시 주석 해제 후 사용
const getHen = () =>
	new Promise((resolve, reject) => {
      setTimeout(() => resolve('🐓'), 1000);
    });
const getEgg = hen =>
	new Promise((resolve, reject) => {
    	setTimeout(() => resolve(`${hen} => 🥚`), 1000);
      // (1)⬇️
      	//setTimeout(() => reject(new Error(`error ${hen} => 🥚`)), 1000);
    });
const cook = egg =>
	new Promise((resolve, reject) => {
      setTimeout(() => resolove(`${egg} => 🍳`), 1000);
    });

getHen() // comment할 주석을 입력하면 prietter를 써도 가독성 있게 라인정리가 된다.
  .then(getEgg)	// .then 은 잘 받아온다면 ()안에 동작을 실행하게 한다.
// (1)⬇️
//  .catch(error => {
//         return '🥖';
//  })
  .then(cook)
  .then(console.log)
// (1)⬇️
// .catch(console.log); 
//상단에서 에러가 나더라도 에러가 제일 밑 catch로 내려가서 잡히게 된다.

//expected result
//error 발생 안할 시 : 🐓 => 🥚 => 🍳
//getEgg에서 error 발생 시 :  🥖 => 🍳

4. async

promise를 좀 더 간단하고 간편하게 동기적으로 실행되는 것처럼 보이게 해준다. promise들을 여러가지 chaining을 해서 사용할 때 (promise함수.then().then()... 형태) 코드가 조금 난잡해 질 수가 있는데 이때 좀 더 간편한 api인 asyncawait을 사용하면 동기식으로 코드를 순서대로 작성하는 것처럼 작성할 수 있게 할 수 있다.

//async 예제
//clear style of using promise 

//1. async
function fetchUser() {
  new Promise((resolve, reject) => {
  	return 'pine';
  });
}
const user = fetchUser();
user.then(console.log);
console.log(user);
//expected result
//Promise{<pending>}
  //_proto_: Promise
  //[[PromiseState]]: "pending"
  //[[PromiseResult]]: undefined
//함수 앞에 async를 붙여주면 자동으로 promise로 바뀌게 된다. async가 promise를 감싸고
//있는 형태이고 이처럼 간편하게 문법은 유지하되 가독성이 좋아지게 하는 문법을 
//Syntactic Sugar라고 한다.
async function fetchUser() {
  return 'pine';
}
//expected result
//Promise{<fulfilled>: "pine"}
  //_proto_: Promise
  //[[PromiseState]]: "fulfuilled"
  //[[PromiseResult]]: "pine"

5. await

await연산자Promise를 기다리기 위해 사용되며 async가 붙은 함수 내에서만 사용 가능하다. await 문은 Promisefulfill되거나 reject 될 때까지 async 함수의 실행을 일시 정지하고, Promisefulfill되면 async 함수일시 정지한 부분부터 실행한다. 이때 await 문의 반환값은 Promise 에서 fulfill된 값이 된다.
만약 Promisereject되면, await 문은 reject된 값을 throw한다.
await 연산자 다음에 나오는 문의 값이 Promise가 아니면 해당 값을 resolved Promise로 변환시킨다.

// await 연산자 예졔
// (1) 번호가 붙은 주석달린 코드는 error handling 할 시에 사용하는 방법을 나타낸다.

async function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function getGrape() {
  await delay(1000);
  // (1)
  //throw 'error'; //에러를 발생시키는 method
  return '🍇';
}

async function getPear() {
  await delay(1000);
  return '🍐';
}

//callback hell 
function pickFruits() {
  return getGrape()
  .then(grape => { return getPear()
  .then(pear => `${grape} + ${pear}`);
  });
}
pickAll().then(console.log);
//expected result : 🍇 + 🍐
//async + await
async function pickFruits() {
  //(1)
  //try {
  const grape = await getGrape();
  const paer = await getPear();
  //} catch() {
  // 여기에 error 발생 시 동작 입력
  //}
  return `${grape} + ${pear}`;
}
pickFruits().then(console.log);
//expected result : 🍇 + 🍐

6. useful Promise APIs(all(), race())

function pickFruits() {
  return Promise.all([getGrape(), getPear()])
    .then(fruits => fruits.join(' + ')
  );
}
pickAllFruits().then(console.log);
//expected result : 🍇 + 🍐

//Promise의 race 함수(getGrape의 delay시간을 2초로 두었다고 가정할 시)
function pickOnlyOne() {
  return Promise.race([getGrape(), getPear()])
pickOnlyOne().then(console.log);

//expected result: 🍐
profile
Better Than Yesterday🌳

0개의 댓글