제대로 파는 자바스크립트(JavaScript) - by 얄코
(https://www.inflearn.com/course/제대로-파는-자바스크립트/dashboard)
목차
14-1. 비동기의 개념과 타임아웃
14-2. 프로미스
14-3. 프로미스의 병렬 진행
14-4. async & await
14-5. 네트워크 통신에서의 활용
14-6. 중간점검 퀴즈
setTimeout 함수
첫 번째 인자로 넣은 콜백 함수를 두 번째 인자로 넣은 수만큼의 밀리 초 후 실행
Web API, Node.js 등 자바스크립트 환경의 기능 (js 언어의 기능이 아님)
비동기 asynchronous 코드
동기 synchronous 코드와 달리 비동기 코드는 순서대로 실행되지 않음
일반적으로 타임아웃, 네트워크 요청 등 시간이 걸리는 작업에 사용
당장 할 수 있는 것들을 먼저 다 하고, 시간이 걸리는 작업은 뒤로 넘기기
(만약 비동기 방식이 없다면 데이터를 받아오는 동안 화면이 어는 등 불편함이 생김)
delay를 생략하거나 0으로 지정할 경우 "즉시", 더 정확히는 다음 이벤트 사이클에 실행한다.
(현재 실행 중인 모든 코드가 끝난 후, 바로 실행)
달리기 경주 예제
1초 ~ 1.5초 사이 무작위 시간 안에 도착
과정 설명
1. 실행 시점에 도착하면 동기 코드 실행
2. 비동기 콜백 코드는 환경(Web API 등)으로 넘겨줌
2-1. 주어진 작업을 마친 작업들은 태스크 큐 task queue 선로로 진입
2-2. 이벤트 루프 event loop: 태스크 큐의 작업이 도착하는대로 자바스크립트 실행도로에 올려놓음
자바스크립트의 코드는 싱글 스레드로 실행
자바스크립트의 실행 환경은 멀티 스레드 (여러 작업들이 동시다발적으로 진행될 수 있음)
* 비동기 콜백 코드는 동기 코드가 모두 실행된 다음 진행됨 (지연 시간을 0으로 해도 나중에 실행되는 이유)
콜백 지옥 callback hell
연속적으로 비동기 코드를 써야하는 경우 콜백 함수 안에 또 다른 콜백 함수를 넣어야하는 상황 발생 (→ 콜백 지옥)
횟수가 많을수록 가독성도 낮아지고 직관성이 떨어짐
릴레이 예제 (콜백 지옥)
철수, 영희, 돌준, 정아, 길돈이 차례로 이어달리기하는 코드
- 각 골인 시간 기록: 이전 콜백함수의 결과가 다음 콜백함수로 넘겨져 축적됨
- 한 주자라도 데드라인(밀리초)을 넘기면 실패: 주자마다 다른 실패 메시지 출력
- 완주 실패 시 '완주 실패 - ${전체 소요시간}' 출력
- 마지막에 '--경기 종료--' 출력
프로미스 promise
어떤 과정 이후 주어진 동작을 실행할 것이란 약속
중첩된 비동기 코드를 직관적이고 연속적인 코드로 작성할 수 있도록 함
생성자 Promise
- 새로운 약속을 하는 코드
- 인자로 받는 콜백함수의 첫 번째 인자 resolve(이름은 관례): 약속 이행 성공 시, 반환할 값 넣어 실행
- 인자로 받는 콜백함수의 두 번째 인자 reject(이름은 관례): 약속 이행 실패 시, 반환할 값 넣어 실행
- reject가 실행되면 resolve는 무시됨
프로미스 인스턴스의 메서드
- then: resolve를 통해 반환된 결과를 인자로 하는 콜백 함수를 넣음
- catch: reject를 통해 (실패로 인해) 반환된 결과를 인자로 하는 콜백 함수를 넣음
- finally: 성공하든 실패하든 실행할 콜백 함수 (필요할 때만 사용)
- 또 다른 프로미스를 반환 (체이닝 가능)
일반적으로 내부에 비동기 코드를 사용
시간이 소모되는 비동기 과정 후 ...을 반환하겠다는 약속
생성자 Promise
- 새로운 약속을 하는 코드
- 인자로 받는 콜백함수의 첫 번째 인자 resolve(이름은 관례): 약속 이행 성공 시, 반환할 값 넣어 실행
- 인자로 받는 콜백함수의 두 번째 인자 reject(이름은 관례): 약속 이행 실패 시, 반환할 값 넣어 실행
- reject가 실행되면 resolve는 무시됨
프로미스 인스턴스의 메서드
- then: resolve를 통해 반환된 결과를 인자로 하는 콜백 함수를 넣음
- catch: reject를 통해 (실패로 인해) 반환된 결과를 인자로 하는 콜백 함수를 넣음
- finally: 성공하든 실패하든 실행할 콜백 함수 (필요할 때만 사용)
- 또 다른 프로미스를 반환 (메서드 체이닝으로 사용)
then은 연속적으로 메서드 체이닝 가능
예제 - 10% 이자, 채무자 파산 가능성 10%, 5번 빌려주기(프로미스로 구현)
예제 - 릴레이(프로미스로 구현)
예제 - 다섯 주자들이 동시에 질주. 데드라인(밀리초) 내에 들어오지 못하면 탈락.
여러 프로미스를 병렬 처리하기 위한 Promise의 정적 메서드들
1. all
- 프로미스의 배열을 받아 동시에 진행
- 모두 성공하면 resolve된 값들을 배열로 반환 (then으로 받음)
- 하나라도 실패하면 catch 실행
성공 시 탑3 표시하기
2. allSettled
- 주어진 프로미스들의 결과를 배열로 출력
- 실패 유무 관계없이 then으로 배열 반환
3. any
- 가장 먼저 성공한 프로미스의 결과를 then으로 반환
- 모두 실패 시 오류 발생
4. race
- 성공이든 실패든 첫 결과물 then 또는 catch로 반환
async 함수
- 프로미스를 기반으로 동작
- 마치 동기 코드처럼 직관적으로 코딩할 수 있음
await: 코드의 진행을 멈추고 프로미스로부터 답을 받아냄
await은 async 함수 또는 모듈 내에서만 사용 가능
예제 - 10% 이자, 채무자 파산 가능성 10%, 5번 빌려주기(async/await)
일반 Promise 문보다 가독성 좋음
reject 가능성이 있는 경우 try ... catch ... finally 문 사용
예제 - 릴레이(async/await)
예제용 서버 요청
링크로 접속하면 아래 파일이 다운로드됨
1. 경기 결과
https://showcases.yalco.kr/javascript/mockserver/race-result
[
{ "runner_idx": 1,
"record": 1454.3881
},
{ "runner_idx": 2,
"record": 1198.4922
},
{ "runner_idx": 3,
"record": 1404.1087
},
{ "runner_idx": 4,
"record": 1218.7154
},
{ "runner_idx": 5,
"record": 1374.5151
}
]
2. 각 선수들 정보 (예시: 1)
https://showcases.yalco.kr/javascript/mockserver/runners/{1~3}
{
"idx": 1,
"name": "홍길동",
"school_idx": 2,
"grade": 3
}
3. 학교 정보 (예시: 1)
https://showcases.yalco.kr/javascript/mockserver/schools/{1~3}
{
"idx": 1,
"name": "복근대학교",
"majors": ["육상", "체조", "투포환"]
}
Fetch API
Web API에서 제공하는 기능 (브라우저 제공)
네트워크로부터 리소스를 받아오기 위한 다양하고 강력한 기능들 제공
이전 방법: HTMLHttpRequest
fetch 메서드
네트워크 통신으로 원격에 요청을 보내고 답을 받아오는 프로미스를 반환
반환되는 결과: { response }
요청의 결과에 대한 정보들을 담은 객체
json 메서드: 결과의 body로 받은 텍스트를 JSON 객체로 변환하여 반환
에러 상황 시(잘못된 주소 등) catch에서 처리
예제용 파일을 json으로 변경한 결과 미리보기
연속 fetching 예제
경기 결과를 받아온 뒤 1등 주자 선택
→ 해당 주자의 상세정보를 반아온 뒤 학교 코드 추출
→ 해당 학교의 정보 받아오기
1. 프로미스 형태로 구현
2. async, await으로 구현
1. 50% 확률로 ‘홀’ 또는 ‘짝’을 반환하는 비동기 작업이 있습니다. 이를 세 번 연속으로 사용하여 그 결과를 쉼표로 구분한 문자열로 받아오려 합니다. 예를 들면 ‘홀, 짝, 홀’, ‘짝, 짝, 홀’과 같은 결과가 3초 후 출력되는 것입니다. 이와 같은 작업을 콜백이 중첩된 코드로 작성해보세요.
예상 답:
function getOddOrEven() {
if (Math.random() < 0.5) {
console.log('홀');
} else {
console.log('짝');
}
}
setTimeout(() => {
getOddOrEven();
setTimeout(() => {
getOddOrEven();
setTimeout(() => {
getOddOrEven();
}, 3000);
}, 3000);
}, 3000);
결과:
정답:
function getOddEven(callback) {
setTimeout(() => {
const res = Math.random() < 0.5 ? '홀' : '짝';
callback(res);
}, 1000);
}
function concatRes(callback) {
getOddEven((res1) => {
getOddEven((res2) => {
getOddEven((res3) => {
const finalRes = res1 + ', ' + res2 + ', ' + res3;
callback(finalRes);
});
});
});
}
concatRes((res) => {
console.log(res);
});
결과:
2. 위 1번의 코드를 Promise를 사용해서 다시 작성해보세요.
예상 답:
function getOddOrEven() {
return new Promise((resolve)=> {
setTimeout(() => {
if (Math.random() < 0.5) {
resolve('홀');
} else {
resolve('짝');
}
}, 3000);
});
}
getOddOrEven()
.then(console.log)
.then(getOddOrEven)
.then(console.log)
.then(getOddOrEven)
.then(console.log);
정답:
function getOddEven() {
return new Promise((resolve) => {
setTimeout(() => {
const res = Math.random() < 0.5 ? '홀' : '짝';
resolve(res);
}, 1000);
});
}
function concatRes() {
let finalRes = '';
return getOddEven()
.then(res1 => {
finalRes += ', ' + res1;
return getOddEven();
})
.then(res2 => {
finalRes += ', ' + res2;
return getOddEven();
})
.then(res3 => {
finalRes += ', ' + res3;
return finalRes;
});
}
concatRes().then(res => {
console.log(res);
});
3. 이번에는 async & await을 사용하는 코드로 다시 작성해보세요.
예상 답:
function getOddOrEven() {
return new Promise((resolve)=> {
setTimeout(() => {
if (Math.random() < 0.5) {
resolve('홀');
} else {
resolve('짝');
}
}, 3000);
});
}
const a = await getOddOrEven();
console.log(a);
const b = await getOddOrEven();
console.log(b);
const c = await getOddOrEven();
console.log(c);
정답:
function getOddEven() {
return new Promise((resolve) => {
setTimeout(() => {
const res = Math.random() < 0.5 ? '홀' : '짝';
resolve(res);
}, 1000);
});
}
async function concatRes() {
const res1 = await getOddEven();
const res2 = await getOddEven();
const res3 = await getOddEven();
return res1 + ', ' + res2 + ', ' + res3;
}
async function execute() {
const res = await concatRes();
console.log(res);
}
execute();
FIN.
[자바스크립트] 섹션 13. 프로토타입 (0) | 2025.05.06 |
---|---|
[자바스크립트] 섹션 12. 스코프와 바인딩 (2) | 2025.05.03 |
[자바스크립트] 섹션 11. 문제들에 대비하기 (0) | 2025.04.13 |
[자바스크립트] 섹션 10. 이터러블과 제너레이터 (0) | 2025.04.13 |
[자바스크립트] 섹션 9. 추가 자료형들 (0) | 2025.04.08 |
댓글 영역