웹풀스택 공부 중
10 - 3. Callback & Promise 본문
개인적으로 제일 어려워하는 부분이지만 화이팅해보자.
Callback
Callback ≠ Asynchronous
- 함수 (= Callback)을 파라미터로 넘겨 (일급 함수), 파라미터를 받은 함수에게 실행권을 넘기는 함수
- “함수를 Parameter로 넘길때, 실행권한도 같이 넘기는 함수이다”
function callback(param1, param2){
console.log(param1 + and + param2)
}
function caller(callback){
callback(arguments[1], arguments[2]);
}
caller(callback, "hello", "goodbye");
arguments[n]
를 사용해 넘겨줄 수 있다- 비동기적인 개념이 아니다
- 비동기적 기능을 가지진 않았지만 비동기에 필수적인 존재이다
- “비동기 로직이 끝나거든 그 비동기 로직의 결과값을 통해 Callback을 실행해주세요”
- 비동기적 기능을 가지진 않았지만 비동기에 필수적인 존재이다
- 비동기의 꽃이긴하다…
- 비동기 함수에게 실행권을 넘기기 위해 Callback을 많이 사용할뿐
Callback Hell
- Callback 결과값이 순차적으로 필요할때 발생한다
- 결과값이 서로 의존되어있다고 보면 된다
- “Callback의 결과가 그 다음 Callback 실행에도 필요한 경우”
Promise
Promise is an object that may produce a signle value some time in the future
Promise = Callback + Asynch
- Asynch (비동기 함수) Caller (= Executor): Producer - 파라미터를 주입한다
- Callback (비동기 처리후 실행할 함수) Callee (= Executee) = Consumer - 파라미터를 받아 수행한다
- Executor에게 자신의 제어권을 넘긴다
- Consumer가 없을 때 Pending Promise가 반환된다
모든 Promise는
결과를 비동기로 생성하고 끝날때 callback을 호출한다
- 두가지 callback을 호출할 수 있다:
sucess
,fail
- 두가지 callback을 호출할 수 있다:
가질 수 있는 상태
Pending (대기): 결과를 기다리는 중 (비동기 처리 로직이 아직 완료되지 않은 상태)
- 먼저
new Promise()
메서드를 호출하면 대기 (Pending) 상태가 된다 new Promise(function(resolve,reject)){ ... }
처럼 콜백 함수(=function)을 선언할 수 있고, Parameter를resolve
와reject
로 줄 수 있다
- 먼저
Fulfiled (이행): 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
위 상태에서
new Promise(...) { resolve() }
를 실행하면 이행 (Fulfiled)상태가 된다이행상태가 된다면
then(...)
을 통해 처리 결과 값을 받을 수 있다function getData() { return new Promise(function(resolve, reject) { var data = 100; resolve(data); }); } // resolve()의 결과 값 data를 resolvedData로 받음 getData().then(function(resolvedData) { console.log(resolvedData); // 100 });
Rejected (실패): 비동기 처리가 실패하거나 오류가 발생한 상태
위 상태에서
new Promise(...) { reject() }
를 호출 시 실패 (Reject)상태가 된다실패 상태가 되면 실패한 이유 (실패 처리의 결과 값)을
.catch()
로 받을 수 있다function getData() { return new Promise(function(resolve, reject) { reject(new Error("Request is failed")); }); } // reject()의 결과 값 Error를 err에 받음 getData().then().catch(function(err) { console.log(err); // Error: Request is failed });
주로 서버에서 받아온 데이터를 화면에 표시할때 사용한다
- 데이터를 달라고 서버에 요청을 보냈으나 받아오기도 전에 데이터를 받아온 것 처럼 화면에 데이터를 표시하려고 할 시 오류가 발생하는것을 방지하기 위함
실제 사용예시
new Promise((resolve, reject) => {
const result = getUserInformationAPI()
if (result.success) { resolve(result.user) }
if (result.failed) { reject({ type: 'No User', message: 'Error Occured' }) }
})
.then((user) => { console.log(user) })
.catch((error) => { console.log(error.message) })
즉,
.then
을 사용해 성공한 결과값을 받고,.catch()
를 사용해 실패한 결과값을 받을 수 있다.finally
를 사용한다면 성공하든 실패하든 실행할 callback함수를 설정해줄 수 있다이것들을 사용하여 Chaining이 가능해진다
ex.)
.then
으로 반환되는 값에 또.then
을 붙일 수 잇따!ex.)
step1(value1) .then((value2) => { return step2(value2) }) .then((value3) => { return step3(value3) }) .then((value4) => { console.log(value4) })
이 방법을 통해 Promise Hell을 해결할 수 있다
- Promise Hell: 결과 값을 순차적으로 연결할 때 발생한다
- Promise의 결과가 그 다음 Promise 실행에 필요한 경우
step1(value1) .then((value2) => { step2(value2) .then((value3) => { step3(value3) .then((value4) => { console.log(value4) }) }) })
- Promise Hell: 결과 값을 순차적으로 연결할 때 발생한다
Async / Await
Promise Hell 해결 방법 2 이다
Async와 Await으로 변환하여 모든 값을 사용할 수 있다
성공 / 실패에 따른 Callback이 존재하지 않기 때문에
- 성공했을때 그대로 값을 쓰면 되지만
- 실패했을때는 Exception처리가 필요하다
try-catch
를 사용하면 된다
위의 Promise Hell을 await으로 변환한 예제
const value2 = await step1(value1) const value3 = await step2(value2) const value4 = await step3(value3) console.log(value4)
더 쉽게 이해해보기
async
= Promise 라는 “상자”를 반환한다- Promise.resolve로 감싸져있으면 바로 반환, 아니면 상자 포장 반환
await
= Promise 라는 “상자”를 연다- Promise 객체가 오기까지 기다렸다가 상자를 열어 내부의 값을 반환한다
async
가 붙은 함수는 반드시 Promise를 반환하고, Promise가 아니더라도 Promise로 감싸 반환한다
async function returnpromise() {
return Promise.resolve(1)
}
returnpromise() // Promise { <fulfilled>, 1 }
await returnpromise() // 1
returnpromise().then(console.log) // 1
// 1이 Promise가 아니여도 Promise로 감쌌다!
async function returnpromise() {
return 1
}
returnpromise() // Promise { <fulfilled>, 1 }
await returnpromise() // 1
returnpromise().then(console.log) // 1
await
키워드를 만다면 Promise가 처리될 때까지 기다린다
async function returningPromise() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('완료!'), 1000)
})
let result = await promise // 위의 Promise가 이행될 때 까지 기다린다
console.log(result)
}
returningPromise()
// 아래의 경우에는 await을 사용하지 않아 바로 Promise가 나와버렸다.
async function returningpromise() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('완료!'), 1000)
});
let result = promise // 프라미스를 기다리지않고, 프라미스 객체 그대로 반환
console.log(result) // Promise { <pending> }
}
returningpromise()