화살표 함수 (Arrow Function)
ECMA Script 2015부터 함수를 선언할 때 `화살표 (=>)`를 사용해서 표현할 수 있게 됨.
`function` 예약어를 사용하지 않고, 함수 이름도 없다.
기본형: `() => {...}`, `(매개변수) => {...}`
화살표 함수에서 실행할 명령줄이 한 줄이라면 중괄호 & return을 생략할 수 있음
let add = (a, b) => {return a+b;}
add(10,20) // 30
// 생략
let add = (a, b) => a + b;
add(10,20) // 30
JS 비동기 처리
동기 처리 & 동기 프로그래밍 (Synchronous)
코드가 위에서 아래로 순차적으로 실행됨
하나의 작업이 끝날 때까지 다음 코드가 실행되지 않으므로 작업이 `블로킹` 될 수 있다.
문제점
네트워크 요청(서버 API 호출) 과 같이 시간이 오래 걸리는 작업을 동기적으로 처리하면, 응답이 올 때까지 프로그램이 멈춤
비동기 처리 & 비동기 프로그래밍 (Asynchronous)
특정 작업이 완료될 때까지 기다리지 않고 다른 작업을 먼저 수행할 수 있음
오래 걸리는 작업을 수행하는 동안 다른 코드가 실행될 수 있어서 효율적
JS에서는 시간이 걸리는 작업이 있을 경우 기본적으로 `비동기`로 처리함
비동기 처리
시간이 걸리는 함수와 빨리 처리할 수 있는 함수가 뒤섞여 있을 때, 함수들을 원하는 처리 순서에 맞게 프로그래밍 하는 것
비동기 프로그래밍 방식
방법 | 버전 | 기능 |
콜백 함수 | 기존부터 사용 | 함수 안에 또 다른 함수를 매개변수로 취함 → `콜백 지옥` |
프로미스 | ECMA Script 2015 | 프로미스 객체, 콜백 함수 사용 |
async / await | ECMA Script 2017 | async / await 예약어를 사용 |
콜백 함수 (Callback)
다른 함수의 `매개변수`로 사용하는 함수
const order = (coffee, callback) => {
console.log(`${coffee} 주문 접수`);
setTimeout(() => {
callback(coffee);
}, 3000);
};
const display = (result) => console.log(`${result} Complete!`);
order('Americano', display);
시간이 얼마나 걸리든 order() 실행 후 display()가 실행되도록 함
익명으로 콜백 함수 작성
function displayLetter() {
console.log('A');
setTimeout(() => {
console.log('A');
setTimeout(() => {
console.log('B');
}, 1000);
setTimeout(() => {
console.log('C');
}, 1000);
setTimeout(() => {
console.log('D');
}, 1000);
setTimeout(() => {
console.log('stop');
}, 1000);
}, 1000);
}
displayLetter(); // A B C D stop
콜백 함수 안에 콜백 함수가 연속으로 들어 있어 가독성이 떨어짐
이렇게 콜백이 계속 반복되는 상태를 `콜백 지옥`이라고 함
Promise
처리에서 성공했을 때와 성공하지 않았을 때 반환 결과 (비동기 연산 결과)를 미리 약속해둔 것
콜백 지옥을 만들지 않기 위해 ECMA Script 2015에 도입
기본 구조
`new Promise`를 사용해서 생성
콜백 함수 내부에서 `resolve()`를 호출하면 성공 상태로 바뀌고, `reject()`를 호출하면 실패 상태가 됨
const myPromise = new Promise((resolve, reject) => {
let success = true; // 성공 여부를 결정하는 변수
setTimeout(() => {
if (success) {
resolve("작업이 성공했습니다!");
} else {
reject("작업이 실패했습니다...");
}
}, 2000);
});
myPromise
.then((result) => {
console.log("성공:", result);
})
.catch((error) => {
console.error("실패:", error);
})
.finally(() => {
console.log("작업 완료!");
});
- then() : resolve()가 호출되었을 때 실행
- catch(): reject()가 호출되었을 때 실행
- finally(): 성공/실패 여부 관계없이 항상 실행
Promise 체이닝 (Chaining)
비동기 작업을 순차적으로 실행하고 싶은 경우, `.then()`을 연결
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => resolve("데이터 로드 완료"), 1000);
});
}
fetchData()
.then((data) => {
console.log(data);
return "다음 작업 실행";
})
.then((message) => {
console.log(message);
})
.catch((error) => {
console.error("에러 발생:", error);
});
- fetchData() 함수는 Promise 반환: 1초 후 Promise가 resolve() 됨
- 첫 번째 .then() 실행: `data`에 `"데이터 로드 완료"` 가 들어감
- 출력: "데이터 로드 완료"
- return 값("다음 작업 실행"): 다음 .then() 으로 전달 - 두 번째 .then() 실행: `message`에 "다음 작업 실행"이 들어감
- .catch() 실행 여부 체크: 에러가 발생한 경우 실행
async / await
비동기 코드를 더 직관적으로 작성할 수 있도록 도와주는 문법
프로미스 체이닝을 계속 연결해서 사용할 경우, 콜백 지옥처럼 코드가 복잡해질 수 있음
이러한 문제를 해결하기 위해 ECMA Script 2017부터 도입
기본형
async function(){
...
await 함수
}
`await` 예약어는 js에서 비동기 코드를 실행할 때 유용, async 함수에서만 사용할 수 있다.
아래는 서버에서 사용자 자료를 가져와 users 변수에 할당한 뒤 터미널 창에 표시하는 코드.
async function init() {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const users = await response.json();
console.log(users);
}
init();
- init 함수 안에서 비동기 처리를 할 예정이므로, async 예약어 붙임
- fetch 함수를 이용해 네트워크를 통해 서버의 자료를 가져옴 (시간 소요)
- 2번이 끝난 후, 프로미스 객체를 프로그램에서 사용할 수 있는 자료로 변경 (`.json()`) (시간 소요)
- 변환된 객체 users를 터미널에 표시