동기적 처리와 비동기적 처리는 javascript를 배우다 보면 자연스럽게 접하게 된다.
오늘은 동기와 비동기가 무엇인지, 차이점은 뭔지 알아보려고 한다.
출처 : https://smallzoodevs-organization.gitbook.io/copy-of-javascript-study/day-05./1.
한눈에 이해되는 그림이 있어서 가지고 왔다.
일상생활에서 보는 동기와 비동기이다. 느낌이 딱 오는 것 같다.
이제는 실제 컴퓨터에서 어떤 작업을 말하는지 알아보자.
우리가 가볍게 쓰는 코드들은 대부분 동기적이라고 보면 된다.
비동기 작업은 굉장이 효율적으로 보인다. 하지만 문제도 있다.
만약 a, b의 작업이 있는데 a의 작업의 결과를 기반으로 b의 작업을 해야한다면?
비동기적으로 했을 때 a가 b보다 빨리 끝난다면 괜찮겠지만,
a가 어떠한 이유로 b보다 작업이 늦게 끝나게 된다면.. b의 작업은 망가지게 된다.
그래서 비동기 작업에도 동기적 표현이 필요하다.
크게 세 가지의 방법이 있다.
- Promise
- Generator
- async / await
Promise는 비동기 처리에 대해, 처리가 끝나면 알려달라는 ‘약속’이다.
new 연산자로 호출한 Promise의 인자로 넘어가는 콜백은 바로 실행되며,
그 내부의 resolve(또는 reject) 함수를 호출하는 구문이 있을 경우 resolve(또는
reject) 둘 중 하나가 실행되기 전까지는 다음(then), 오류(catch)로 넘어가지 않는다.
따라서, 비동기작업이 완료될 때 비로소 resolve, reject이 호출된다.
let myFirstPromise = new Promise((resolve, reject) => { // 우리가 수행한 비동기 작업이 성공한 경우 resolve(...)를 호출하고, // 실패한 경우 reject(...)를 호출한다. // 이 예제에서는 setTimeout()을 사용해 비동기 코드를 흉내낸다. setTimeout(function () { resolve("성공!"); // 문제 없음! }, 250); }); myFirstPromise.then((successMessage) => { // successMessage는 위에서 resolve(...) 호출에 제공한 값. // 위에서 문자열을 줬으니 아마 문자열일 것이다. console.log("와! " + successMessage); // 와! 성공! });
*가 붙은 함수가 제너레이터 함수이다.
제너레이터 함수는 실행하면, Iterator(반복이라고 생각하자.) 객체가 반환(next()를 가지고 있음)된다.
next 메서드 호출시, Generator 함수 내부에서 가장 먼저 등장하는 yield 에서 stop.
이후 다시 next 메서드를 호출하면 멈췄던 부분 -> 그 다음의 yield 까지 실행 후 stop한다.
즉 ,비동기 작업이 완료되는 시점마다 next 메서드를 호출해주면 Generator 함수 내부소스가 위 -> 아래 순차적으로 진행된다.
function* generator() { yield 1; yield 2; yield 3; } const gen = generator(); // "Generator { }" console.log(gen.next().value); // 1 console.log(gen.next().value); // 2 console.log(gen.next().value); // 3
ES2017에서 새롭게 추가된 async/await 문이다.
비동기 작업을 수행하고자 하는함수 앞에 async를
함수 내부에서 실질적인 비동기 작업이 필요한 위치마다 await를 붙여주면 된다.
암시적으로 Promise를 사용하여 결과를 반환한다.
function resolveAfter2Seconds() { return new Promise((resolve) => { setTimeout(() => { resolve('resolved'); }, 2000); }); } async function asyncCall() { console.log('calling'); const result = await resolveAfter2Seconds(); console.log(result); // Expected output: "resolved" } asyncCall();
promise를 사용한 코드를 async를 사용한 코드로 바꿔줄 수 있다. 아래 예시를 보자.
function getProcessedData(url) { return downloadData(url) // returns a promise .catch((e) => { return downloadFallbackData(url); // returns a promise }) .then((v) => { return processDataInWorker(v); // returns a promise }); }
위 코드는 아래로 변경이 가능하다.
async function getProcessedData(url) { let v; try { v = await downloadData(url); } catch (e) { v = await downloadFallbackData(url); } return processDataInWorker(v); }
위 예제에서는 return 구문에 await 구문이 없는데,
이는 async function의 반환값이 암묵적으로 Promise.resolve
로 감싸지기 때문이다.
이번에 콜백 함수를 배우면서 동기 비동기를 배웠는데, 이전에 nodejs로 프로젝트를 하면서 async / await를 많이 사용했었다. (어떻게 동작하는지도 모르고..)
사실 100프로 이해했다고는 못하지만 머릿속에 정리가 되는 느낌이다.
어렵지만.. 나 화이팅...