Promise 객체
Consumers
Promise 는 "약속하다" 라는 뜻이다. 약속하다라는 이름이 붙은 이유는 값을 보장하기 때문이다. 어떤 작업이 실패하든 성공하든, Promise 객체는 성공하면 값을 가지고, 실패하면 에러 값을 가진다. 결국 성공하든 실패하던 무조건 결과를 가지게 된다.
비동기 작업의 코드는 두 가지로 나뉜다.
Producing code 는 시간이 걸리는 코드이다. 예를 들면 서버에서 데이터를 불러오는 코드다.
Consuming code 는 producing code 의 결과를 원하는 코드이다. 예를 들면 서버에서 불러온 닉네임을 주황색으로 만들고자 하는 코드이다.
Promise 는 producing code 와 consuming code 를 연결해주는 자바스크립트 객체이다. 비유를 하자면 Promise 는 "구독자 리스트"이다. producing code 가 시간을 들여 결과를 내면, Promise 는 그 결과를 원하는 consuming code 들 (구독자들) 이 결과를 사용할 수 있도록 제공한다.
let promise1 = new Promise(()=> (resolve, reject)) {
// executor (producing code)
resolve(result); // 성공 시
reject(error); // 실패 시
}
Promise
객체는 new
키워드를 이용하여 생성할 수 있다. 생성자(constructor)의 인자로 annonymous function 이 들어가는데, 이 함수를 executor 라고 한다. Promise 객체가 생성되는 순간 executor 는 자동으로 실행된다. Executor 는 producing code 를 가지며, 어떠한 결과를 내놓을 것이다.
Executor 는 반드시 두 개의 callback 함수를 인자로 가져야 한다.
resolve(value)
- 작업이 성공했을 시 호출될 함수. 인자 : 결과값.
reject(error)
- 작업이 실패했을 시 호출될 함수. 인자 : 에러 객체.
Promise 객체의 모양은 전에 callback 으로 error handling 을 만들었던 것과 비슷하다. 즉 Promise 는 error handling 과 chaining 을 JavaScript 자체에서 지원하는 것이라고 볼 수 있다.
Promise 객체는 state
(상태)와 result
(결과) 라는 두 속성을 가진다.
3가지의 상태가 있고, 상태에 따라 결과값이 다르다.
(Promise 객체를 console.log()
출력하면 두 속성의 상태를 볼 수 있다.)
state | result |
---|---|
초기값 : "pending" | undefined |
resolve 호출 시 : "fulfilled" | value |
reject 호출 시 : "rejected" | error |
(Promise 의 속성에 직접 접근할 수는 없다.)
Executor 가 resolve
나 reject
둘 중 하나를 호출하기 전까지 Promise 객체의 상태는 pending
이다.
// State: <Pending>
let promise1 = new Promise((resolve, reject)=> {});
console.log(promise1);
// Promise {State: "pending", Result: undefined}
// State: <fullfilled>
let promise2 = new Promise((resolve, reject)=> {
resolve("Hello");
});
console.log(promise2);
// Promise {State: "fullfilled", Result: "Hello"}
// State: <rejected>
let promise3 = new Promise((resolve, reject)=> {
reject(new Error("Whoops!");
});
console.log(promise3);
// Uncaught (in promise) Error: Whoops!
// reject()의 인자로 아무 값이나 넣을 수 있지만 Error 객체를 사용하는 것이 권장된다.
// Error 객체는 나중에 알아보자.
resolved 되거나 rejected 된 Promise 는 "setteled" 되었다고 부른다.
앞서 말했듯 Promise 객체는 executor (producing code) 와 executor 가 내놓은 결과를 원하는 consuming code 사이를 연결해주는 역할을 한다. Consuming code 는 .then()
, .catch()
, .fianlly()
로 등록을 할 수 있다. 이 세 함수는 Promise 객체의 메서드이다. 즉 Promise 인스턴스로만 호출할 수 있다.
가장 핵심적인 함수이다. then()
에는 두개의 인자가 들어간다.
첫번째 인자는 Promise 가 resolved 되었을 때 실행될 함수이다. 이 함수는 결과값을 인자로 받아 필요한 작업을 수행한다.
두번째 인자는 Promise 가 rejected 되었을 때 실행될 함수이다. 이 함수는 error 를 인자로 받는다.
promise1.then(
(result)=> { /* result 를 가지고 필요한 작업을 수행 */ },
(error)=> { /* error 를 처리 */ }
)
.then
을 사용한 예제는 다음과 같다.
// Promise 가 resolve 되었을 때
let promise1 = new Promise((resolve, reject)=> {
setTimeout(()=> { resolve("done!"), 1000 });
});
// Promise 가 reject 되었을 때
let promise1 = new Promise((resolve, reject)=> {
setTimeout(()=> { reject(new Error("Whoops!")), 1000 });
});
promise1.then(
(result)=> { console.log(result) },
(error)=> { console.log(error) }
)
// 혹은 resolved 되었을 때만 관심이 있다면 then 에 함수를 하나만 제공할 수도 있다.
promise.then(console.log);
// console.log 가 인자 없이도 작동이 가능하다는건 처음 알았다. alert 도 마찬가지였다.
// 에러가 나는지만 체크하고 싶다면, then 의 첫 번째 인자로 null 을 넣어도 된다.
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("에러났어요.")), 1000);
});
promise1.then(null, console.log);
promise1.catch(console.log);
// 위 두 코드는 같은 동작을 수행한다.
// catch 는 내부적으로 then(null, f) 로 설계되어 있다.
// catch is an "analog" of then(null, f)
만약 catch
가 chain 의 중간에 있다면, catch 전에 에러가 날 경우 catch 가 실행되고, catch 이후에 then 들이 호출된다. (추가적인 catch 가 없다면 에러를 잡아낼 수 없다.)
만약 catch
가 chain 의 끝에 있다면, 중간에 에러가 날 경우 catch 가 실행된 후 에러 이후의 코드들은 작동하지 않는다.
Promise 에서 에러 핸들링은 try...catch
와 비슷하게 작동한다.
Error handling | JavaScript.info - try catch 에 관해
Error handling with promises | JavaScript.info - Promise 와 try catch 와의 관계
finally
는 Promise 의 결과가 resolve 든 reject 든 무조건 수행해야 할 작업이 있을 때 사용한다. 예를 들어 성공하든 실패하든 로딩화면을 끝내야 할 때, finally()
안에 로딩창을 없애는 코드를 넣으면 된다. 어쨌든 finally 도 then, catch 와 마찬가지로 Promise 가 setteled 된 후에 실행된다.
promise1.finally(()=> { 로딩화면 종료하기 })
.then((result)=> { result 보여주기 },
(error)=> { error 보여주기 })
finally
의 annoymous function 은...
Promise chaining
https://javascript.info/promise-chaining