특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고, 순차적으로 다음 코드를 실행하는 것 non-blocking 이라고도 한다. 하지만 Ajax로 데이터를 불러오기 전에 바로 다음 코드를 실행시켜 오류를 발생시킬 수 있다.
비동기적으로 코드를 빠르게 실행시키고 싶지만 정해진 순차를 컨트롤 하기 위해 생겨난 문법들이다.
const printString = (string, callback) => { //printString이란 변수에 string과 callback함수를 파라미터로 받아온다.
setTimeout( //JS 내장메소드로 있는 몇초 후에 값을 반환 할 것인지 정해준다.
() => {
console.log(string) //string값을 console에 나타내주고
callback() // 콜백함수를 즉시 실행한다.
},
Math.floor(Math.random() * 100) + 1 //1~100까지 중에 정수를 랜덤하게 나타내고 소수점은 버린다.
)
}
const printAll = () => { //printAll이란 변수에 콜백함수를 실행
printString("A", () => { //printString 함수를 불러와서 argument를 준다.
printString("B", () => { //A라는 스트링과 콜백함수 호출로 A를 호출한 다음 B를 호출
printString("C", () => {}) //B를 호출한 다음 C를 호출한다.
})
})
}
printAll()
생성자 함수와 동일하게 new로 Promise 객체를 만들 수 있다. 이 때 인자로는 Executor가 들어가는 데 Executor 는 resolve 와 reject 라는 두 개의 함수를 매개변수로 받는 실행함수이다. Executor 는 비동기 작업을 시작하고 모든 작업을 끝낸 후, 해당 작업이 성공적으로 이행이 되었으면 resolve 함수를 호출하고, 중간에 오류가 발생한 경우 reject 함수를 호출
var timeAttack = new Promise(function (resolve, reject) {
setTimeout(function () {
var ran = Math.random() * 10;
if (ran >= 5) {
resolve(ran);
} else {
reject();
}
}, 1000);
});
이 경우에 timeAttack 이라는 Promise 객체는 3가지 상태를 가진다.
대기(pending) : 아직 실행되지 않은 초기 상태
이행(fulfilled) : 작업이 성공적으로 완료됨.
거부(rejected) : 작업이 실패함.
작업이 성공적으로 이행이 되었거나, 실패 했을 때, 어떠한 작업을 해야 하는데 이 작업은 then 메소드에 의해 실행된다. 이는 callback함수를 실행한 것과 같은 효과를 낸다. then 메소드는 promise객체에 붙여서 사용한다.
timeAttack.then(function (num) {
console.log(num + 'complete');
}, function () {
console.log('error');
});
promise.then(successCallback, failureCallback) 이러한 방식으로 콜백을 실행할 수 있다.
then() Method
then 메소드는 promise객체를 리턴하고 두 개의 콜백 함수를 인수로 받는다. 사용 형태는 다음과 같다.
promise.then(successCallback, failureCallback)
promise.then(function (value) {
//성공했을 때 실행
}, function (reason) {
//실패했을 때 실행
});
위에 적은 successCallback 은 promise가 성공(fulfilled)했을 때를 위한 콜백 함수이고, failureCallback 은 실패(rejected)했을 때를 위한 콜백 함수이다.
then 메소드는 promise 객체를 리턴하고 인수로 받은 콜백 함수들의 리턴 값을 이어 받는다. 따라서 chaining이 가능하다. 아래의 예제처럼.
var promise = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(1);
}, 1000);
});
promise.then(function (num) {
console.log(num + 'complete'); /// 1complete
return num + 1; /// return = 2
}).then(function (value) {
console.log(value) // 2
});
resolve에 인자로 들어간 숫자 1이 첫번째 then() 메소드를 거치면서 +1이 되고 두번째 then() 메소드에서는 2가 되었다. 이처럼 promise를 리턴하는 then의 특성으로 계속해서 체이닝 패턴이 사용 가능하고, 값을 조작할 수 있다.
Promise 이전의 비동기 처리는 Callback함수를 설정하는 방식으로 이루어졌다. 비동기가 완료되는 시점에 실행이 되는 callback함수로 완료를 인지하고 그 다음을 처리한 것이다. 그렇게 하다보니 비동기 처리를 연속적으로 해야하는 경우 Callback함수에 Callback함수가 들어가고 거기에 또 Callback함수가 들어가는 이상하고 요상한 코드가 되어 버렸다. 이것을 이른바 Callback Hell 이라고 한다.
a(function (resultA) {
b(resultA, function (resultB) {
c(resultB, function (resultC) {
d(resultC, function (resultD) {
//OMG.....
});
});
});
});
Promise를 이용하여 이러한 Callback Hell을 말끔히 탈출할 수 있는 것은 아니지만 Callback을 함수로 바로 넘겨받지 않고 객체에 이어서 사용할 수 있게 되면서 훨씬 보기 쉬워졌다.
promise.then(function(a){
}).then(function(b){
}).then(function(c){
}).then(function(d){
});