비동기 호출 포스팅에서 callback함수로 순차적 비동기 호출을 구현 할 때 콜백 지옥이란 문제점이 존재하며, 콜백 지옥을 개선하기 위한 방식이 있다고 했었다.
Promise가 콜백 지옥을 타파하고 비동기 작업을 하기위해 ES6부터 도입된 방식이다.
callback hell은 비동기 처리시 함수의 파라미터로 넘겨지는 콜백함수가 반복되어 코드 들여쓰기가 깊어지는 것을 말한다.
아래 코드로 A, B, C, D를 출력한다면 실행시마다 랜덤으로 출력될 것이다.
let printString = string => {
setTimeout( () => console.log(string) , Math.floor(Math.random() * 1000)+1)
}
let printAll = () => {
printString('A')
printString('B')
printString('C')
printString('D')
}
printAll();
callback함수를 이용해 A, B, C, D를 순차적으로 실행하도록 만들어 준다면 아래처럼 쓸 수 있다.
let printString = (string, callback) => {
setTimeout( () => {
console.log(string)
callback();
}, Math.floor(Math.random() * 1000)+1)
}
let printAll = () => {
printString('A', () => {
printString('B', () => {
printString('C', () => {
printString('D', () => {}
});
});
});
}
printAll();
처리해야할 데이터가 4개임에도 코드의 들여쓰기가 깊어지고 가시성이 떨어진다. 만약 처리해야할 데이터가 수 십개라면 이야말로 콜백 지옥이 되버린다.
앞 서 언급했던 것과 같이, Promise는 callback함수의 대안으로 등장했으며 비동기 처리를 위한 객체이다.
callback을 인자로 주지 않고, return 값을 새로운 promise 객체로 준다.
new Promise(resolve, reject => {});
executor(실행 함수)로 들어오는 resolve와 reject는 자체적으로 제공되는 콜백함수이다.
promise 객체에는 3가지 상태가 존재한다.
case1. 함수가 값을 반환하지 않을 때, undefined
를 결과값으로 갖는다.
let printFunc = () => {
return new Promise((resolve, reject) => {
resolve()
});
}
printFunc().then((value) => {
console.log(value)
}); //undefined
resolve에 인자를 담아가더라도 return을 하지 않으면 undefined
를 갖는다.
let printFunc = () => {
return new Promise((resolve, reject) => {
resolve('Hello')
});
}
printFunc().then((value) => {
console.log(value)
}); //Hello
case2. 함수가 값을 반환할 때 리턴값을 결과값으로 갖는다.
printFunc().then((value) => {
console.log(value)
return value;
});
let failFunc = () => {
return new Promise((resolve, reject) => {
reject(new Error('It is failed'))
})
}
failFunc().then().catch(err => {
console.log(err)
})
여러개의 promise들을 연결해서 사용하는 것을 말한다.
예를 살펴보자.
함수마다 Promise 객체를 생성해서 setTimeout()
으로 1초 후에 resolve()
를 호출해주었다.
function gotoCode() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve('1. go to code')},1000)
});
}
function sitAndCode() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve('2. sit and code')},1000)
});
}
function eatLunch() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve('3. eat lunch')},1000)
});
}
function gotoBed() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve('4. go to Bed')},1000)
});
}
resolve()
를 부르게 되면 대기 상태에서 이행 상태로 넘어오며 첫번째 then()
이 실행되고, 반환값을 받아서 두번째 then()
인자로 넘겨준다.
두번째 then()
에서도 마찬가지로 반환값을 받아서 세번째 then()
의 인자로 넘겨주는 체이닝 형태가 된다.
gotoCode()
.then(data => {
console.log(data)
return sitAndCode()
})
.then(data => {
console.log(data)
return eatLunch()
})
.then(data => {
console.log(data)
return gotoBed()
})
.then(data => {
console.log(data)
})
1초마다 출력된다.
여러 개의 promise를 처리할 때 사용된다.
Promise.all(iterable)
promise.all의 인자는 Array와 같이 iterable한 객체가 오며, 인자 배열의 요소로 Promise가 들어온다.
const getDataFromFile = filePath => {
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf-8', (err, data) => {
if(data) {
resolve(data.toString());
}
reject(err); //reject에는 에러메세지를
});
});
};
const readAllUsers = () => {
return Promise.all([getDataFromFilePromise(user1Path), getDataFromFilePromise(user2Path)]) //배열을 준거고 배열의 요소가 promise이다.
.then((datas) => {
return datas.map(el => JSON.parse(el));
})
Promise 실행함수가 가지고 있는 두 개의 파라미터, resolve, reject는 각각 무엇을 의미하나요?
resolve : 비동기 처리가 완료될 때 결과값
reject : 비동기 처리가 실패하거나 오류 날 때 결과값
resolve, reject함수에는 인자를 넘길 수 있습니다. 이때 넘기는 인자는 어떻게 사용할 수 있나요?
.then, .catch의 인자로 들어가 사용한다.
Promise.prototype.then 메소드는 무엇을 리턴하나요? Promise를 리턴
Promise.prototype.catch 메소드는 무엇을 리턴하나요?
promise를 리턴
Promise의 세가지 상태는 각각 무엇이며, 어떤 의미를 가지나요?
Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태
Fulfilled(이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
Rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태