아직 클래스를 다루진 않았지만,
클래스와 인스턴스화 클래스는 객체를 만드는공장
같은 것으로,
이러한 공장에서 객체를 만들 때 인스턴스화한다고 한다.
자바스크립트에서 비동기처리를 간편하게 처리할 수 있도록 제공하는 객체
정해진 기능을 수행했다면 결과값을 반환하고, 처리하지 못했을 때에는 error를 반환한다
Promise 클래스를 인스턴스화해서 promise 객체를 만든다
이렇게 만든 promise 객체를 통해 비동기 작업을 한다.
Promise는 클래스이기 때문에 new 생성자를 통해 인스턴스화해서 객체를 만든다.
let promise = new Promise(function(resolve, reject) {
// 비동기로직
});
Pending (대기)
: 비동기 처리 로직이 아직 완료되지 않음Fulfilled (이행)
: 비동기 처리가 완료되어 Promise가 결과값을 반환해준 상태Rejected (실패)
: 비동기 처리가 실패하거나 오류가 발생한 상태then의 콜백함수 handler function
는 여러 타입의 반환이 가능하다
첫 번째 then의 return값이 그 다음 then의 콜백함수의 매개변수로 들어간다
let promise = new Promise(function(resolve, reject) {
// 비동기상황
setTimeout(function() {
resolve(1); // 1초뒤에 성공하면 실행
}, 1000);
});
promise
.then(function(first) {
console.log('first', first);
return 2;
}).then(function(second) {
console.log(second);
});
반환된 promise 안에 있는 resolve는 그 다음에 있는 then 안에 있는 콜백함수이다.
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(1);
}, 1000);
});
promise
.then(function(first) {
console.log('first', first);
return 2;
})
.then(function(second) {
console.log('second', second);
// 두 번째 then의 콜백함수에서 promise를 return 한다
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(3);
}, 1000);
});
})
.then(function(third) {
console.log('third', third);
});
콜백함수 종류 | 특징 |
---|---|
resolve | 비동기 로직이 성공했을 때 실행 |
reject | 비동기 로직이 실패했을 때 실행 |
1. promise 객체의 then이나 catch 메서드를 통해 resolve, reject 함수를 정의한다
resolve, reject 또한 함수이기 때문에 미리 정의를 해야한다고 생각할 수 있겠지만,
미리
정의하지 않아도 자바스크립트 엔진에서 정의해놓기 때문에 에러가 발생하지 않는다
아예 정의를 하지 않는다는 것이 아니라 이후에 .then()
메서드에서 첫 번째 인자로 resolve, 두 번째 인자로 reject 함수를 정의한다
만약 API 호출에 성공했을 때 받은 응답값을 토대로 차트를 그리겠다고 하면,
promise 객체에 then 메서드
를 통해 차트를 그리는 로직을 써 넣으면 된다
let promise = new Promise(function(resolve , reject) {
setTimeout(function() {
resolve('hello world'); // 로직이 성공했을 때
reject('good bye'); // 로직이 실패했을 때 + 단 여기서는 실행되지 않는다
}, 2000);
});
promise.then(function(msg) {
console.log('resolve', msg);
}, function(msg) {
console.log('reject', msg);
});
// 실행결과 : resolve hello world
2. resolve, reject는 비동기 콜백함수이기 때문에
처음에 호출된 한 문장
만 실행한다.
3. Promise 내부의 비동기 로직이 실패했을 때 error 객체를 통해 reject 콜백함수에 전달한다.
const promise = new Promise(resolve, reject) => {
console.log('doing something...');
setTimeout(() => reject(new Error('no network')), 2000);
}
promise
.then(value => {
console.log(value);
})
.catch(error => {
console.log(error);
})
.finally(()=> console.log('finally'));
코드설명
여러 개의 비동기 작업을 순차적으로 해야 할 때 사용한다
예시
순차적으로 각각의 작업이 이전 단계의 비동기 작업이 성공하고 나서 그 결과값을 이용해 다음 비동기 작업을 실행하는 경우
getProducts()
.then(getComments)
.then(getLikes)
resolve 콜백함수
에서 어떻게 반환하냐에 따라 다르게 처리할 수도 있다reject를 호출
하거나 reject를 호출해서 then의 두 번째 인자를 정의
하는 것 대신,catch
를 사용하는 것이 대부분이다.Promise 에러처리 방법
- reject
- catch
getHen()
.then(getEgg) // 여기서 만약 에러가 발생한다면
.catch(error => { // 다음 줄 catch를 통해 에러처리가능
return 'bread'
})
.then(cook)
.then(console.log);
.catch(console.log);
// 실행결과 : bread => fried edd
💡 받아온 하나의 valuw를 콜백함수에서 매개변수로 바로 사용한다면, 생략할 수 있다
// ====생략 전 ====
getHen()
.then(hen => getEgg(hen))
.then(egg => cook(egg))
.then(meal => console.log(meal));
// ====생략 후 ====
getHen() // prettier 에서 한줄로 되기 때문에 주석표시를 해주면 여러줄이 된다
.then(getEgg)
.then(cook)
.then(console.log);
실행순서는 동기함수 → 비동기함수 이기 때문에
결과적으로 콘솔창에 1, 3, 2 순서로 찍히게 된다
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(1);
resolve(2);
console.log(3);
resolve(4);
}, 1000);
});
promise.then(function(data) {
console.log(data);
});
let promise = new Promise(function(resolve, reject) {
console.log(1);
setTimeout( function() {
resolve(2);
}, 1000)l;
});
promise.then(function(data) {
console.log(data);
});
바벨
을 이용하면 좋다function job() {
return new Promise(function(resolve, reject) {
reject();
});
}
job()
.then(function() {
console.log(1);
})
.then(function() {
console.log(2);
})
.then(function() {
console.log(3);
})
.catch(function() {
console.log(4);
})
.then(function() {
console.log(5);
});
/* 실행결과
4
5
*/
promise에서 reject를 호출했기 때문에 맨 처음 콘솔에 4가 찍히고,
한 편으로는 catch 메서드에서 promise를 리턴하기 때문에 아래의 then도 같이 실행되기 때문에 콘솔에 5도 찍힌다
function job(state) {
return new Promise(function(resolve, reject) {
if (state) {
resolve('success');
} else {
reject('error');
}
});
}
job(true)
.then(function(data) {. // 첫 번째 then
console.log(data);
return job(false);
})
.catch(function(error) { // 두 번째 catch
console.log(error);
return 'Error caught';
})
.then(function(data) {. // 세 번째 then
console.log(data);
return job(true);
})
.catch(function(error) { // 네 번째 catch
console.log(error);
});
처음에 promise에서 state=true이기 때문에 resolve를 호출해서 첫 번째 then 콜백함수가 실행된다
reject(‘error’)가 호출되면 두 번째 catch의 콜백함수가 실행된다
이전에 일반값이 리턴되었기 때문에 세 번째 then의 콜백함수의 매개변수 data = ‘Error caught’ 가 들어가게 된다
class UserStorage {
loginUser(id, password, onSucess, onError) {
setTimeout(()=>{
if (
(id === 'ellie' && password === 'dream') ||
(id === 'coder' && password === 'academy')
) {
onSucess(id);
} else {
onError(new Error('not found'));
}
}, 2000)
}
getRoles(user, onSuccess, onError) {
setTimeout(()=> {
if (user === 'ellie') {
onSuccess({ name: 'ellie', role: 'admin' });
} else {
onError(new Error('no access'));
}
}, 1000);
}
}
const userStorage = new UserStorage();
const id = prompt('enter your id');
const password = promt('enter ypur password');
userStorage.loginUser
(id,
password,
user => {
userStorage.getGRole(
user,
userWithRole => {
alert(`Hello ${userWithRole.name}, you have a ${userWithRole.role} role.`)
},
error => { console.log(error) })
},
error => {
console.log(error)
}
);
class UserStorage {
loginUser(id, password) {
return new Promise(resolve, reject) => {
setTimeout(()=>{
if (
(id === 'ellie' && password === 'dream') ||
(id === 'coder' && password === 'academy')
) {
resolve(id);
} else {
reject(new Error('not found'));
}
}, 2000);
}
}
getRoles(user) {
return new Promise((resolve, reject) => {
setTimeout(()=> {
if (user === 'ellie') {
onSuccess({ name: 'ellie', role: 'admin' });
} else {
onError(new Error('no access'));
}
}, 1000);
})
}
}
const userStorage = new UserStorage();
const id = prompt('enter your id');
const password = promt('enter ypur password');
userStorage
.loginUser(id, password)
.then(userStorage.getRoles)
.then(user => alert(`Hello ${userWithRole.name}, you have a ${userWithRole.role} role.`)
.catch(console.log);