특정 코드의 실행이 끝날 때까지 기다려주지 않고 다음 코드를 먼저 실행하는 것.
동기보다 복잡하지만 결과가 주어지는데 시간이 걸리더라도 그 시간동안 다른 작업을 할 수 있으므로 자원을 효율적으로 사용할 수 있는 장점이 있다.
function getData() {
var tableData;
// HTTP GET 요청을 날려 1번 상품(product) 정보를 요청
// 받아온 데이터는 response 인자에 담김
$.get('https://domain.com/products/1', function(response) {
tableData = response;
});
return tableData;
}
console.log(getData()); // undefined
callback 함수에는 두 가지 정의가 있다.
//hello!
function printHello(){ print('hello'); }
//bye!
function printBye(){ print('bye'); }
//특정 함수를 매개변수로 받아서 3초 뒤에 실행하는 함수
function sleepAndExecute(sleepTimeSecond, callback){
//sleepTimeSecond 초 만큼 대기
sleep(sleepTimeSecond);
//전달된 callback 실행
callback(); }
//3초 뒤에 hello 출력하기
sleepAndExecute(3, printHello);
//5초 뒤에 bye 출력하기
sleepAndExecute(5, printBye);
이 때 printHello
와 printBye
함수는 sleepAndExcute
함수의 매개변수로 이용되므로 callback 함수라고 할 수 있다.
function onCableConnected(){ print("케이블이 연결되었습니다"); };
//케이블이 연결될 때 마다 전달된 onCableConnected가 호출된다고 가정
setOnCableConnected(onCableConnected);
setOnCableConnected
가 케이블을 연결할 때마다 호출되므로, onCableConnected
는 callback 함수라고 할 수 있다.
이러한 callback 함수를 사용하면 특정 로직이 끝났을 때 원하는 동작을 실행시킬 수 있다.
function getData(callbackFunc) {
$.get('https://domain.com/products/1', function(response) {
callbackFunc(response); // 서버에서 받은 데이터 response를 callbackFunc() 함수에 넘겨줌
});
}
getData(function(tableData) {
console.log(tableData); // $.get()의 response 값이 tableData에 전달됨
});
서버에서 데이터를 받아와 화면에 표시하기까지 모든 과정을 비동기로 처리한다면?
콜백 안에 콜백을 무는 형식으로 코딩을 하게 된다.
$.get('url', function(response) {
parseValue(response, function(id) {
auth(id, function(result) {
display(result, function(text) {
console.log(text);
});
});
});
});
Promise는 new Promise()
메소드를 호출하여 비동기 작업을 생성/시작하는 객체이다.
동작에 대한 결과를 올바르게 줄 수 있다면 resolve
, 동작을 실패했다면 reject
함수를 호출한다.
Promise에는 크게 세 가지 상태(states)가 있다.
먼저 아래와 같이 new Promise()
메서드를 호출하면 대기(Pending) 상태가 된다.
new Promise();
new Promise()
메서드를 호출할 때 콜백 함수를 선언할 수 있고, 콜백 함수의 인자는 resolve
, reject
이다.
new Promise(function(resolve, reject) {
// ...
});
여기서 콜백 함수의 인자 resolve
를 아래와 같이 실행하면 이행(Fulfilled) 상태가 된다.
new Promise(function(resolve, reject) {
resolve();
});
그리고 이행 상태가 되면(resolve
함수가 실행되면) 아래와 같이 then()
을 이용할 수 있다. 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
});
콜백 함수의 인자 reject
를 아래와 같이 호출하면 실패(Rejected) 상태가 된다.
new Promise(function(resolve, reject) {
reject();
});
실패 상태가 되면(reject
함수가 실행되면) catch()
을 이용할 수 있다. 실패한 이유를 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
});
위의 내용을 종합하여 다음과 같은 Promise 코드를 만들 수 있다.
function getData() {
return new Promise(function(resolve, reject) {
$.get('url 주소/products/1', function(response) {
if (response) {
resolve(response);
}
reject(new Error("Request is failed"));
});
});
}
// 위 $.get() 호출 결과에 따라 'response' 또는 'Error' 출력
getData().then(function(data) {
console.log(data); // response 값 출력
}).catch(function(err) {
console.error(err); // Error 출력
});
Promise.all()
은 모든 Promise가 이행될 때까지 기다렸다가 그 결과값을 담은 배열을 반환하는 메서드이다.
여러개의 Promise가 모두 리졸브 된 후, 다음 로직을 실행해야 하는 경우에 사용한다. 복수의 URL에 request를 보내고, 모든 요청의 응답이 올때 화면을 렌더 해야하는 상황이 그 예시이다.
let urls = [
'https://www.example.com/users/1',
'https://www.example.com/product/2',
'https://www.example.com/article/3'
];
// fetch를 사용해 url을 프라미스로 매핑
let requests = urls.map(url => fetch(url));
// Promise.all은 모든 작업이 리졸브 될 때까지 대기
Promise.all(requests)
.then(responses => responses.forEach(
response => alert(`${response.url}: ${response.status}`)
));
이 때, 입력된 Promise 배열이 하나라도 리젝트 되면 Promise.all()
또한 리젝트 된다.
Promise의 가독성 문제를 개선한 비동기 처리 패턴이다.
함수 앞에 async
를 붙이면 해당 함수는 항상 Promise를 반환한다.
async
함수 안에서 await
키워드를 만나면 반환된 Promise가 처리(fulfilled 또는 rejected)될 때까지 기다린다. 결과는 그 이후 반환된다.
function fetchItems() {
return new Promise(function(resolve, reject) {
var items = [1,2,3];
resolve(items)
});
}
async function logItems() {
var resultItems = await fetchItems();
console.log(resultItems); // [1,2,3]
}
fetchItems
함수를 실행하면 Promise가 이행(fulfilled)되며 결과 값은 items
가 된다.
logItems()
함수를 실행하면 fetchItems()
의 결과 값이 resultItems
변수에 담긴다.
만약 이 때 await
를 사용하지 않았다면, callback 함수나 .then()
을 사용해야 했을 것이다.
자바스크립트 async와 await
[Javascript] 비동기, Promise, async, await 확실하게 이해하기
[메모] Promise.all