-
[JavaScript] 비동기 (Asynchronous)Study/JavaScript 2024. 8. 22. 20:25
동기 vs 비동기
동기(Synchronous) 비동기(Asynchronous) 요청과 응답이 순차적으로 발생 요청과 응답이 비순차적으로 발생 요청에 대한 응답이 올 때까지 대기한 후
다음 요청 및 작업을 수행요청에 대한 응답을 기다리지 않고
바로 다음 요청 및 작업을 수행동기적 처리(Synchronous Processing)는 작업의 처리 순서는 보장되지만, 응답을 기다리는 동안 다른 작업을 수행할 수 없기 때문에 비효율적일 수 있음
비동기 작업을 동기적으로 처리하는 방법
콜백(Callback) 함수
콜백(callback) 함수 : 다른 함수의 인자로 들어가는 함수
각 비동기 함수들을 콜백 함수 형태로 중첩적으로 작성
const test = () => { setTimeout(() => { console.log("작업1 진행중"); setTimeout(() => { console.log("작업1 완료"); setTimeout(() => { console.log("작업2 진행중"); setTimeout(() => { console.log("작업2 완료"); setTimeout(() => { console.log("작업3 진행중"); setTimeout(() => { console.log("작업3 완료"); setTimeout(() => { console.log("모든 작업 종료"); }, 1000); }, 1000); }, 1000); }, 1000); }, 1000); }, 1000); }, 1000); }; test(); /* 작업1 진행중 작업1 완료 작업2 진행중 작업2 완료 작업3 진행중 작업3 완료 모든 작업 완료 */단점 : 많은 콜백 함수를 중첩적으로 사용하면 가독성이 떨어질 수 있음
각 함수별로 이름을 붙여 작성
// 작업1 const doFirst = (callback) => { setTimeout(() => { console.log("작업1 진행중"); setTimeout(() => { console.log("작업1 완료"); callback(); }, 1000); }, 500); }; // 작업2 const doSecond = (callback) => { setTimeout(() => { console.log("작업2 진행중"); setTimeout(() => { console.log("작업2 완료"); callback(); }, 1000); }, 500); }; // 작업3 const doThird = (callback) => { setTimeout(() => { console.log("작업3 진행중"); setTimeout(() => { console.log("작업3 완료"); callback(); }, 1000); }, 500); }; // 실제 작업 const test = () => { doFirst(() => { doSecond(() => { doThird(() => { setTimeout(() => { console.log("모든 작업 종료"); }, 500); }); }); }); }; test();장점
: 함수별로 이름이 붙여져 가독성이 나아짐
단점
: 그럼에도 여전히 중첩적으로 사용할 경우, 가독성이 떨어질 수 있음
: 계속된 이름 생성 발생
Promise
비동기 작업을 수행하고 성공(Resolve) 또는 실패(Reject)를 반환하는 객체
Promise 객체의 상태
Pending(대기중) 초기 상태, 비동기 작업이 아직 수행되지 않음 Fulfilled(성공) 비동기 작업이 성공적으로 완료됨
resolve 메서드를 통해 상태를 pending → fulfilled로 변경Rejected(실패) 비동기 작업이 실패하거나 오류가 발생함
reject 메서드를 통해 상태를 pending → rejected로 변경const myPromise = new Promise((resolve, reject) => { // 비동기 작업 수행 if (/*성공*/) { resolve(/*성공시 수행할 작업*/); } else { reject(/*실패시 수행할 작업*/); } });- 함수 표현
// AS_IS (callback 함수) const doFirst = (callback) => { setTimeout(() => { console.log("작업1 진행중"); setTimeout(() => { console.log("작업1 완료"); callback(); }, 1000); }, 500); }; // TO_BE (Promise 객체) const doFirst = () => { return new Promise((resolve) => { setTimeout(() => { console.log("작업1 진행중"); setTimeout(() => { console.log("작업1 완료"); resolve("작업1 완료"); // resolve 값 반환 }, 1000); }, 500); }); };- 실제 작업
// AS_IS (callback 함수) const test = () => { doFirst(() => { doSecond(() => { doThird(() => { setTimeout(() => { console.log("모든 작업 종료"); }, 500); }); }); }); }; // TO_BE (Promise 객체) const test = () => { doFirst() .then(doSecond) .then(doThird) .then(() => { setTimeout(() => { console.log("모든 작업 종료"); }, 500) }); };실패 또는 오류가 발생했을 경우 catch문을 활용
const success = true; // 성공 // 함수 표현 const doFirst = () => { return new Promise((resolve, reject) => { setTimeout(() => { if(!success) { console.log("작업1 완료"); resolve("작업1 완료"); // 성공시 resolve 값 반환 } else { console.log("작업1 실패"); reject("작업1 실패"); // 실패시 reject 값 반환 } }, 1000); }, 500); }; // 실제 작업 const test = () => { doFirst() .then(doSecond) .then(doThird) .then(() => { setTimeout(() => { console.log("모든 작업 종료"); }, 500) }) .catch(() => { // 에러 발생시 console.log("에러 발생"); }); };여러 개의 비동기 작업을 동시에 처리하는 방법
: Promise.all 또는 Promise.allSettled 메서드를 사용
공통점
: 모든 Promise 객체의 작업이 완료될 때까지 기다림
차이점
- Promise.all
- 모든 Promise 객체가 fulfilled인 경우에만 최종적으로 fulfilled를 반환
- Rejected인 Promise 객체가 하나라도 존재하면 최종적으로 rejected를 반환
- 최종적으로 나온 fulfilled/rejected에 대해 작업을 수행
- Promise.allSettled
- 각 Promise 객체의 결과를 배열 형태로 반환
- Promise의 결과가 fulfilled면 resolve 값을 value로 반환
- Promise의 결과가 rejected면 reject 값을 reason으로 반환
- 최종적으로 나온 fulfilled/rejected에 대한 작업을 각각 수행
- 각 Promise 객체의 결과를 배열 형태로 반환
[ {status: "fulfilled", value: "작업1 완료"}, {status: "rejected", reason: "작업2 실패"} ]
Async & Await
async Promise 객체를 반환하는 키워드 await Promise 객체의 작업이 끝날 때까지 함수의 실행을 일시중단하는 키워드 // AS_IS (Promise ~ then) const test = () => { doFirst() .then(doSecond) .then(doThird) .then(() => { setTimeout(() => { console.log("모든 작업 종료"); }, 500) }); }; // TO_BE (async/await) const test = async () => { await doFirst(); await doSecond(); await doThird(); setTimeout(() => { console.log("모든 작업 종료"); }, 500); };장점
: 콜백함수 없이 동기적 코드처럼 작성할 수 있음
: 가독성이 좋아짐
실패 또는 오류가 발생했을 경우 try~catch문을 활용
const test = async () => { try { await doFirst(); await doSecond(); await doThird(); setTimeout(() => { console.log("모든 작업 완료"); }, 500); } catch (error) { console.log("에러 발생"); } };'Study > JavaScript' 카테고리의 다른 글
[JavaScript] 정규 표현식 (Regex) (0) 2026.01.08 [JavaScript] ES6 이후 주요 문법 (0) 2024.08.12 [JavaScript] 주요 내장 객체 (문자열, 객체, 배열) 메서드 (0) 2024.08.09 [JavaScript] 변수 & 데이터 타입 (0) 2024.08.05