기록
Promise, async/await 본문
1. 프로미스
: 내용이 실행은 되었지만, 결과를 아직 반환하지 않은 객체.
: 자바스크립트 비동기 처리를 위한 객체
실행 자체는 동기로 함.
원할 때(=then을 붙였을 때) 결과를 반환함.
즉, 코드를 분리할 수 있다!(콜백함수와의 차이점)
기본적으로 프로미스를 new Promise로 생성하는데,
그 내부에 resolve와 reject를 매개변수로 갖는 콜백함수를 넣음. 이 부분은 동기로 실행됨!
new Promise() 이 부분은 동기로 실행됨!
물론 실행은 됐으나, 결과값은 then이나 catch 메서드를 통해 받음.
이 부분은 프로미스가 가지고 있는 값임.
(프로미스는 내부까지는 동기임. 그러나 then을 만나는 순간 비동기로 감.)
const condition = true; //true면 resolve, false면 reject
const promise = new Promise((resolve, reject) => {
if (condition) {
resolve('성공');
} else {
reject('실패');
}
};
일단 프로미스가 들고 있다가 나중에 원할 때 꺼낼 수 있음.
바로 아래처럼.
promise
.then((message) => {
console.log(message);
})
.catch((error) => {
console.log(error);
})
.finally(() => {
console.log('무조건');
});
실행이 완료되지 않았으면 완료된 후에 then 내부 함수가 실행됨
성공하면 resolve()를 호출 -> then으로 연결
실패하면 reject()를 호출 -> catch로 연결
finally 부분은 무조건 실행됨
콜백과 가장 큰 차이점은,
콜백은 일단 무조건 그 콜백함수를 가지고 있어야 함.
다음 예시처럼, setTimeout 안에 callback을 무조건 들고 있어야 함.
function callback() {};
setTimeout(callback, 3000);
일반적으로 자바스크립트의 비동기 처리 코드는 콜백을 사용해야지 코드의 실행 순서를 보장받을 수 있음.
프로미스는 이와 달리 코드를 분리할 수 있다는 큰 특징.
일단 실행해놓고, 다른 동작을 실컷하다가 필요할 때 then을 붙여서 가져올 수 있음.
const promise = setTimeoutPromise(3000);
console.log('딴짓');
console.log('딴짓');
console.log('딴짓');
console.log('딴짓');
console.log('딴짓');
promise.then(() => {
console.log('지금 할래!');
});
그래서 코드가 깔끔해짐
또한, 그 유명한 콜백지옥! 중첩되는 문제를 깔끔하게 해결함.
Promise.all 은 여러 프로미스를 동시에 실행하는데, 하나라도 실패하면 catch로 감.
요즘은 all 보다 allSettled를 많이 쓴다고 함.
2. async/await
에이싱크 어웨이트도 프로미스인데, 프로미스를 한 번 더 깔끔하게 줄임
.then
.then
.then 이것들을 더 줄여보자이거지.
async function 함수명() {
await 비동기_처리_메서드_명();
}
await이 then 역할을 함.
"먼저 함수의 앞에 async 라는 예약어를 붙입니다. 그러고 나서 함수의 내부 로직 중 HTTP 통신을 하는 비동기 처리 코드 앞에 await를 붙입니다. 여기서 주의하셔야 할 점은 비동기 처리 메서드가 꼭 프로미스 객체를 반환해야 await가 의도한 대로 동작합니다. 일반적으로 await의 대상이 되는 비동기 처리 코드는 Axios 등 프로미스를 반환하는 API 호출 함수입니다.(캡틴판교님)"
//before
function findAndSaveUser(Users) {
Users.findOne({})
.then((user) => {
user.name = 'zero';
return user.save();
})
.then((user) => {
return Users.findOne({ gender: 'm' });
})
.then((user) => {
//생략
})
}
기존에는
프로미스 Users.findOne() 을 실행하고
.then(결과값user) 이런 방식이라면,
//after
async function findAndSaveUser(User) {
let user = await Users.findOne({});
user.name = 'zero';
user = await user.save();
user = await Users.findOne({ gender: 'm' });
//생략
}
aync, await은 오른쪽에서부터 실행된다는 느낌으로,,
Users.findOne이라는 프로미스가 성공해서 then(=await) 되면 결과값이 user에 저장.
변수 = await 프로미스; 인 경우 프로미스가 resolve된 값이 변수에 저장됨
변수 = await 값; 인 경우 그 값이 변수에 저장됨
추가 예시(캡틴판교)
function fetchItems() {
return new Promise(function(resolve, reject) {
var items = [1,2,3];
resolve(items)
});
}
async function logItems() {
var resultItems = await fetchItems();
console.log(resultItems); // [1,2,3]
}
async 함수 안에 return 값이 있다면?
async function main() {
const result = await promise;
return 'zerocho';
}
1) main().then((name) => ... );
2) const name = await main()
async/await도 프로미스이기 때문에 프로미스 문법을 따름.
그래서 then으로 가져올 수도 있고, 아니면 배운대로 await으로.
단, async/await은 reject를 처리할 부분이 없어서 try, catch로 감싸줘야 함
async function main() {
try {
const result = await promise;
} catch (error) {
console.log(error);
}
}
또한, 화살표함수도 async/await이 가능함
const findAndSaveUser = async (Users) => {
try {
let user = await Users.findOne({});
//생략
} catch (error) {
console.error(error);
}
};
for await ( 변수 of 프로미스배열)
const promise1 = Promise.resolve('성공1');
const promise2 = Promise.resolve('성공2');
(aync () => {
for await (promise of [promise1, promise2]) {
console.log(promise);
}
})();
반복문을 돌리면서 then(=await)을 붙일 수 있음
+) 실무에서 prototype에 대한 이해가 많이 중요한가요?
제로초님의 경우는 함수 위주로 하기 때문에 거의 안쓰지만,
클래스로 만들 수 있는 것도 다 함수로 하고 그럼.
클래스기반으로 객체지향프로그래밍 하는 사람들은 많이 씀.
다른 사람의 라이브러리를 분석하거나 할 때 함수형일 수도, 객체지향일 수도 있으니까
코드를 이해하려면 모두 알고 있어야 함..
코드를 자유자재로 짤 수 있으면 거기서 한 단계 더 나아가기 위해서는 다른 사람의 코드도 읽을 줄 알아야 함.