자바스크립트에서 비동기를 처리할 때 callback과 promise를 사용하게 된다. 이둘의 차이점을 callback hell 뿐만 아니라 명확하게 알기 위해 정리한다.
function async(callback) {
setTimeout(() => {
callback("1초 후 실행");
}, 1000);
}
async(function (msg) {
console.log(msg);
});
async 함수는 첫번째 인자로 callback을 받고, callback이 실행될 때 첫 번째 인자를 console에 출력한다.
callback이 실행되는 시점은 async 함수 안에 있는 setTimeout으로 인해서 1초 후에 실행이 된다. callback이 실행이 되면서 첫번째 인자로 '1초후 실행'이 들어가고, 콘솔에 '1초 후 실행'이 나타나게 된다.
이렇게 callback을 통해서 어떠한 비동기 로직이 끝났을 때 callback 함수를 실행시키므로써 비동기 작업이 완료 되었을 때 callback에서 작성한 어떠한 행동을 실행할 수 있게 된다.
promise 객체는 new 키워드와 함수를 인자로 받는 생성자를 통해서 생성할 수 있다. 여기서 인자로 받는 함수는 resolve와 reject라는 2개의 파라미터를 가진다.
function async(key) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (key === true) resolve("waited 1 sec.");
else reject(new Error("Error!"))
}, 1000);
})
}
async(true)
.then((result) => { console.log(result); })
.catch((error) => { console.log(error); });
promise를 사용하면 resolve는 성공했을 때, reject는 에러가 발생했을 때 첫번째 인자로 어떠한 값을 넘길 수 있다. resolvesms .then의 첫번째 인자로, reject는 .catch의 첫번째 인자로 들어간다.
async 함수에 true를 넣어 실행하면 1초 후,
resolve의 "waited 1 sec"이 .then의 첫번째 인자로 전달되어 "waited 1 sec"이 콘솔에 찍히고, false를 넣어 실행하면 1초 후
reject의 new Error("Error!")가 .catch의 첫번째 인자로 전달되어 "Error: Error! at" 가 콘솔에 찍힌다.
callback을 사용하면 비동기 로직의 결과값을 처리하기 위해서는 callback 안에서만 처리를 해야되고, 콜백 밖에서는 비동기에서 온 값을 알 수가 없습니다. 하지만 promise를 사용하면 비동기에서 온 값이 promise 객체에 저장되기 때문에 코드 작성이 용이해집니다.
function async(callback) {
var result;
setTimeout(() => {
result = callback("결과값");
},1000);
return result;
}
var b = async((res) => {
return res;
})
만약 async 함수에서 비동기가 끝난 후의 값을 가지고 싶어서 위처럼 코드를 썼다면, b를 1초 후, 100초 후에 찍어도 undefined만 나오게 된다.
var p = new Promise((res, rej) => {
setTimeout(() => {
res("a")
}, 1000)
})
var result = p.then(res => {
return res;
})
console.log(result) // Promise {<fulfilled>: "a"}
result.then(res => {
console.log(res); // "a"
})
promise를 사용하게 되면 promise 객체에 비동기가 처리된 결과값이 저장됩니다. 콜백의 경우 매번 비동기를 실행해야지 그 값을 사용할 수 있지만 프로미스는 .then 메소드를 통해서 저장되어 있는 값을 원하는 때에 사용할 수 있습니다.
function async(result, callback) {
setTimeout(() => {
callback(result, function (result) {
console.log(result);
});
}, 1000);
}
async(0, function (res, callback) {
callback(res)
async(res + 1, function (res, callback) {
callback(res)
async(res + 1, function (res, callback) {
callback(res)
});
});
});
// 0
// 1
// 2
위처럼 비동기 로직의 결과를 다음 비동기로 전달해서 실행해야 할 때 callback은 깊어질수 있음 -> callback hell이 발생하며 가독성이 매우 안좋아질 수 있다.
function async(result) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(result);
resolve(result);
}, 1000)
});
}
async(0).then(res => {
return async(res + 1);
}).then(res => {
return async(res + 1);
})
// 0
// 1
// 2
프로미스를 사용할 경우 .then을 통해 코드의 깊이가 깊어지지 않고, 이해하기도 쉬워진다.