
2025 / 02 / 17
오늘 수업 시간에는 동기식 / 비동기식 프로그래밍에 대해 배웠습니다.
항상 헷갈렸었는데, 다른 사람에게 설명하면서 공부하니 조금 더 괜찮았습니다.
그 다음에는 Promise 객체에 대해 배웠습니다. 정보처리산업기사에서 개념으로만 접했던 내용을 실제로 사용해보고 이해하는 시간을 가졌습니다.
Synchronous Programming
- 동기식 프로그래밍은 순차적으로 작업을 처리하는 방식입니다.
- 한 작업이 끝난 후에 다음 작업을 실행합니다.
- 첫 번째 작업이 완료되기 전까지는 두 번째 작업이 실행되지 않습니다.
function synxWork() {
const delayUntil = new Date().getTime(); // 현재 시간을 밀리초로 반환
const twoSecondLater = delayUntil + 2000; // 2초 뒤의 시간 계산
// 현재 시간이 2초가 지날 때까지 기다림
while (Date.now() < twoSecondLater);
console.log("완료");
}
console.log("hello");
synxWork(); // 2초 동안 기다림
console.log("world");
Asynchronous Programming
- 비동기식 프로그래밍은 작업을 동시에 진행할 수 있는 방식입니다.
- 어떤 작업이 끝나지 않아도 다른 작업을 실행할 수 있게 해줍니다.
- 주로 시간이 오래 걸리는 작업을 처리할 때 유용합니다.
function asyncWork() {
setTimeout(() => {
console.log("완료");
}, 2000); // 2초 후에 '완료' 출력
console.log("작업시작");
}
asyncWork(); // '작업시작'이 먼저 출력되고, 2초 후에 '완료'가 출력됩니다.
Callback Hell
- 콜백 함수는 특정 작업이 완료된 후 호출되는 함수입니다.(비동기 방식에서 주로 사용)
- 작업을 완료하는 시점을 알리거나 그 후에 다른 작업을 실행할 때 유용합니다.
- 중첩된 콜백 함수를 사용하면 코드가 깊이 중첩되어 관리하기 어려워집니다.
- 콜백 함수가 중첩된 이러한 현상을 콜백 헬이라고 합니다.
function callback() {
setTimeout(() => {
console.log("작업 완료1");
setTimeout(() => {
console.log("작업 완료2");
setTimeout(() => {
console.log("작업 완료3");
setTimeout(() => {
console.log("작업 완료4");
}, 2000);
}, 2000);
}, 2000);
}, 2000);
}
callback();
- 프로미스는 비동기 작업의 완료 또는 실패를 다루는 객체입니다.
- 비동기 작업이 완료되었을 때 성공 / 실패를 처리하는 방식입니다.
- 콜백 함수 대신 사용합니다.
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("성공"); // 2초 후에 성공 메시지 전달
}, 2000);
});
promise.then((message) => {
console.log(message); // '성공'이 출력됨
});
- 프로미스를 사용하면 여러 개의 비동기 작업을 순차적으로 실행할 수 있습니다.
- 아래의 예시는 1초, 2초, 3초 후에 순차적으로 메시지를 출력하는 예시입니다.
const getPromise1 = (second) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`프로미스 1 ${second}`);
}, second * 1000);
});
};
const getPromise2 = (second) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`프로미스 2 ${second}`);
}, second * 1000);
});
};
const getPromise3 = (second) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`프로미스 3 ${second}`);
}, second * 1000);
});
};
getPromise1(1)
.then((message) => {
console.log(message); // 1초 후에 '프로미스 1 1' 출력
return getPromise2(2);
})
.then((message) => {
console.log(message); // 2초 후에 '프로미스 2 2' 출력
return getPromise3(3);
})
.then((message) => {
console.log(message); // 3초 후에 '프로미스 3 3' 출력
});
- then( ) 메서드는 반환된 프로미스를 이어서 실행할 수 있게 해줍니다.
- 콜백 헬을 피하고 코드의 가독성을 높이는 데 유용합니다.
- catch( ) 메서드를 사용하여 오류를 처리할 수 있습니다.
- finally( )는 비동기 작업이 성공하든 실패하든 항상 실행되는 메서드입니다.
- 주로 클린업 작업이나 마지막 처리를 할 때 사용됩니다.
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("error"); // 2초 후에 오류 발생
}, 2000);
});
promise2
.then((message) => {
console.log("성공", message);
})
.catch((error) => {
console.log("실패", error); // '실패 error' 출력
})
.finally(() => {
console.log("마지막"); // 성공/실패 여부 관계없이 항상 실행
});
- 프로미스를 간단하게 표로 정리해보았습니다!
| 용어 | 설명 | 사용 예시 |
|---|---|---|
| Promise | 비동기 작업의 완료 또는 실패를 처리하는 객체입니다. 작업이 완료되었을 때 resolve 또는 reject를 통해 상태를 변경합니다. | let promise = new Promise((resolve, reject) => { resolve("성공"); }); |
| resolve | 성공적인 결과를 전달합니다. | resolve("작업 완료!"); |
| reject | 오류 메시지를 전달합니다. | reject("오류 발생!"); |
| then( ) | resolve가 호출된 후 실행되는 메서드입니다. 비동기 작업이 성공적으로 완료되었을 때 그 결과를 처리합니다. | promise.then(result => { console.log(result); }); |
| catch( ) | reject가 호출된 후 실행되는 메서드입니다. 비동기 작업이 실패했을 때 오류를 처리합니다. | promise.catch(error => { console.log(error); }); |
| finally( ) | 비동기 작업이 성공하거나 실패하든 관계없이 항상 실행되는 메서드입니다. | promise.finally(() => { console.log("마지막 처리"); }); |
| 체이닝 | 여러 개의 then( )을 이어서 사용할 수 있어, 비동기 작업을 순차적으로 처리할 수 있습니다. | promise.then(result => { return nextPromise; }).then(result => { ... }); |
- 따로 작성해서 정리한 간단한 예시 입니다.
// 프로미스 예시
const examplePromise = new Promise((resolve, reject) => {
const isSuccess = true; // 성공 여부
if (isSuccess) {
resolve("작업 성공!");
} else {
reject("작업 실패!");
}
});
examplePromise
.then((message) => {
console.log(message); // "작업 성공!" 출력
})
.catch((error) => {
console.log(error); // "작업 실패!" 출력
})
.finally(() => {
console.log("마지막 처리 완료"); // 항상 실행
});
- HTTP 요청을 보내고 응답을 처리할 수 있는 javascript의 내장 함수입니다.
- 이 함수는 url을 입력받아 요청을 보냅니다.
- 그 후 서버에서 돌아온 응답을 비동기적으로 처리할 수 있게 해줍니다.
- fetch( )는 Promise 객체를 반환합니다.
- 네트워크 요청이 성공적으로 완료되면 resolve 상태로 데이터를 반환하고, 실패하면 reject 상태로 에러를 반환합니다.
fetch(url)
.then(response => {
// 응답이 성공적으로 돌아왔을 때 실행되는 코드
})
.catch(error => {
// 에러가 발생했을 때 실행되는 코드
});
- 가장 기본적인 fetch( )의 예시는 서버에서 데이터를 받아오는 것입니다.
- then( )과 catch( ) 메서드를 사용하여 응답을 처리할 수 있습니다.
fetch("https://randomuser.me/api/")
.then((response) => {
return response.json(); // 응답을 JSON 형식으로 변환
})
.then((data) => {
console.log(data); // 받아온 데이터 출력
console.log(data.results[0].gender); // 첫 번째 사용자 성별 출력
})
.catch((error) => {
console.error("Error:", error); // 에러 처리
});
fetch("https://randomuser.me/api/")
https://randomuser.me/api/라는 URL에서 랜덤 사용자 데이터를 요청하고 있습니다.then((response) => response.json())
then((data) => {...})
catch((error) => {...})
1) CORS
- 다른 도메인에서 데이터를 요청할 경우 CORS 정책에 의해 요청이 차단될 수 있습니다.
- 서버 측에서 CORS 헤더를 설정해주어야 합니다.
2) 에러 처리
- 네트워크 오류나 잘못된 응답이 올 수 있으므로 catch()를 사용하여 반드시 오류를 처리해야 합니다.
3) 응답 상태 코드
- fetch( )는 요청이 성공했는지, 실패했는지에 대한 정보를 제공하지 않습니다.
- 서버가 404 오류를 반환해도 fetch()는 정상적으로 처리된 것처럼 보일 수 있습니다.
- 이 경우 응답 객체의 response.ok 속성을 확인해 상태를 처리할 수 있습니다.
fetch("https://example.com/api")
.then((response) => {
if (!response.ok) {
throw new Error("Network response was not ok");
}
return response.json();
})
.then((data) => console.log(data))
.catch((error) => console.error("error", error));
fetch( ) 전체적인 순서
1) fetch( )로 API에 요청을 보냅니다.
2) 응답이 성공적이었는지 확인합니다.
3) 성공적이면 데이터를 JSON 형식으로 변환해줍니다.
4) 실패하면 오류 메시지를 던지고, catch( )에서 그 오류를 처리하게됩니다.
29일차 후기
- 비동기식과 동기식에 대한 내용은 산업기사 준비할 때 들어봐서 아는 내용이었습니다.
- 하지만 프로미스 객체 부분은 듣기만 하고 사용해 본 경험은 없어서.. 실습하면서 조금 신기하기도 했고 중간에 약간 헷갈리는 부분도 있어서 곤란했습니다.
- 모르는 건 예시를 더 찾아보고 투두리스트를 만들 때 날씨 api를 적용했던 것을 떠올리며 전체적으로 어떤 흐름을 갖고 있는지 이해하려고 노력한 것 같습니다.
- 아직은 자연스럽게 사용은 못하겠지만! 언젠가는 할 수 있겠죠..? ꒰๑˃͈꒳˂͈๑꒱ノ