코드 순서가 작업 순서와 마찬가지. 순차적으로 call stack(first in, last out)에 넣어지고, 넣어지자마자 바로바로 실행됨
→ fetch
, setTimeout
과 같은 Web API에서 제공되는 비동기 처리 함수를 이용할 수 있다.
ex.
setTimeOut(callback, milliseconds)
setTimeOut
: 실행될 callback function을 지정된 시간 후에 실행되도록 예약(queue)하는 함수. → 기존의 프로그램 흐름에서 벗어나 asynchronous하게 실행됨.⇒ fetch
와 같은 API를 사용할 시, API request에 대한 response는 asynchronous할 것.
(서버에 요청을 보내면 요청이 올 때까지 시간이 좀 걸림 → 요청이 전부 수행될때까지 브라우저를 무작정 멈추어 둘 수는 없으므로, 서버의 요청이 도착하면 데이터 처리 코드를 실행하도록 aynchronous한 방식으로 코드를 작성해야 한다.)
callback : function의 파라미터로 다른 function definition을 넣는 것.
→ callback pattern : asynchronous한 코드를 작성하기 위해 callback을 이용할 수 있다.
success callback : 함수 수행 성공 이후 실행되는 asynchronous callback
welcomeUser
에서 두 번째 인자로 전달해주는 callback은 success callback이다.// usage
welcomeUser("Sam", () => {
console.log("Done welcoming user");
});
// definition
const welcomeUser = (name, callback) => {
setTimeOut(() => {
console.log(`Welcome ${name}`);
callback(); //success callback
}, 1_000);
}
reason => {console.error(reason);
), 주로 success callback 다음 순서의 인자로 입력된다.export const sumGrades = (grades, callback) => {
// simulate expensive operation
setTimeout(() => {
const sum = grades.reduce((total, current) => total+current, 0);
if (callback) {
callback(sum); // call success callback with the sum
}
}, 1_000);
}
const calculateSum = (grades) => {
sumGrades(grades, result => {
console.log(`The sum is : ${result}`);
});
}
calculateSum([18,10]);
Promise: Promise의 결과에 따라 callback을 수행할 수 있게 하는 wrapper의 일종이라고 생각할 수 있음.
→ Promise를 이용하여 asynchronous code를 작성하는 것이 보다 직관적인 syntax
e.g.1. callback을 이용할 경우 생길 수 있는 callback hell ..
sumTemperatures(temperatures, value => {
console.log(value);
}, reason => {
console.error(reason);
});
→ promise : .then
과 .catch()
로 함수 실행 순서를 정해줄 수 있으므로 callback 인자 순서를 상관하지 않아줘도 됨, 보다 직관적.sumTemperatures(temperatures)
.then(value => {
console.log(value);
})
.catch(reason => {
console.error(reason);
});
그래서 promise가 뭔데?
비유 : 키오스크에서 음식 주문 후 받는 번호표가 Promise object와 비슷하다고 볼 수 있다. (주문 후 아직 음식이 없지만, 음식이 될 수 있는 것.)
주문이 그냥 배달될수도(resolve) 취소될수도(rejected) 있고, .then()
, .catch()
method로 배달과 취소 각각의 경우를 다룰 수 있다. (e.g. then() : 음식이 됨, catch() : 음식이 되지않음 ..)
.then()
, .catch()
: Promise를 반환하는 함수에만 쓸 수 있는 method. fetch
와 getUserMedia
등 여러 WebAPI가 promise를 활용하기 때문에 중요하다.
→ 각각 Promise 실행 성공/실패의 경우 무엇을 할지를 다룬다.
e.g. 아래 wait()
함수 : 인자로 기다릴 시간을 받고, promise를 결과로 반환
const wait = milliseconds => {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, milliseconds);
}, reject => {
reject("function rejected");
});
}
→ 반환되는 Promise의 파라미터 :
resolve
: success callback과 같은 역할, wait.then(resolve)
와 같은 형식으로 전달됨.
reject
: error callback과 같은 역할, wait.catch(reject)
와 같은 형식으로 전달된다.
⇒ 이때 .then()
과 .catch()
는 wait이 반환하는 Promise에 불러져서 promise에 callback을 전달해주는 역할을 함.
wait(1_000).then(() => {
console.log("waited 1 second");
})
.catch(() => {
console.log("rejected");
});
;
pending : promise가 외부 함수에 의해 반환되었지만 아직 실행되지 않은 상태 (e.g. 성공/실패 결과가 정해지지 않음)
fulfilled : promise 실행이 성공하여 이에 따른 success callback의 실행까지 완료됨
→ promise가 fulfilled 상태가 되면 .then(callback)
이 실행된다
rejected : promise가 성공적으로 실행되지 못했을 때의 state (ex. API 응답이 네트워크 이슈로 성공적으로 수령되지 못했을 때)
→ 이때 실행할 에러 처리용 callback을 .catch(callback)
으로 전달해줌으로써 에러를 다루는 로직을 구현할 수 있음(에러메시지 띄우기 등)
e.g. :
console.log(wait(1_000));
// console : Promise {<pending>}
const result = wait(1_000);
console.log(result);
// console : Promise {<pending>}
→ Promise의 callback 실행을 위해서는 1초가 지나야 하기 때문에, 함수를 부르고 난 직후의 출력은 상태를 보여준다.
const result = wait(1_000);
console.log(result);
// Promise {<pending>}
result.then(() => {
console.log(result);
// Promise {<fulfilled: undefined>}
});
console.log(result);
// Promise {<pending>}
→ wait()
이 반환하는 promise가 result에 담겨있으므로, result에 .then
을 사용할 수 있다.
⇒ result.then() 안의 console.log(result)
만 promise가 fulfilled 상태가 된 이후 실행되므로, 출력값은 아래와 같다
Promise {<pending>}
Promise {<pending>}
Promise {<fulfilled: undefined>}
const function = (parameter) => {
// Executor!
return new Promise((resolve, reject) => {
/* 함수에서 실행할 statement들 */
resolve(); // promise가 성공적이면 실행될 .then(callback)
reject(); // promise가 실패하면 실행될 .catch(callback)
});
}
이때 Promise가 초기화될때 받는 argument를 executor(()⇒{})
이라고 한다. resolve()
함수는 executor의 첫번째 인자이다. reject()
함수는 executor의 두번째 인자이다. .then(resolve)
으로 전달되는 resolve
함수는, argument로 외부에서 전달될 data를 넣어줌으로써 이를 활용할 수 있다. ⇒ resolve(data)
e.g. 실제 구현의 경우 외부 API에서 반환되는 data를 활용하는 코드를 작성할 수 있다.const wait = milliseconds => {
return new Promise(resolve => {
setTimeout(() => {
resolve(milliseconds / 1_000);
}, milliseconds);
});
}
wait(2_000).then((data) => {
console.log(data); // 2
});
executor의 두번째 callback argument는 Promise가 rejected state일때 실행되는 .catch(callback)
과 동일한 reject()
함수이다.
resolve()
와 같이 reject()
도 함수의 data를 전달받아 이용할 수 있다.
const alwaysFail = () => {
return new Promise((resolve, reject) => {
reject("Failed. That's the only thind I do.");
});
}
alwaysFail()
.then(() => {
// never called
}).catch(data => {
console.error(data);
});
resolve, reject와 같이 promise에서 실행하는 callback들도 Promise를 반환할 수 있다. 이 경우 다음과 같은 promise chaining이 가능하다.
fetch("some-url")
.then(response => response.json())
.then(data => {
console.log(data);
});
Promise.finally()
:.then()
은 promise가 성공적으로 실행돼서 fulfilled 상태가 되면 수행하고, .catch()
는 promise 실행에 실패해서 rejected 상태가 되면 실행한다. .finally()
는 fulfilled든 rejected든 상관없이 pending 상태에서 벗어나면 callback을 실행한다. .then()
과 .catch()
에서 공통적으로 실행하는 statement가 있으면, .finally()
로 깔끔하게 넣어줄 수 있음. (e.g. console.log(”finished”);
) startLoader();
stopLoader()
함수를 가상의 API 함수 getWeatherIn()
의 시작과 끝에 각각 두고 싶을 때 (기상정보가 반환됐을 때 loader을 안보이게 하는 등)startLoader();
getWeatherIn("Amsterdam")
.then(data => {
console.log(data);
})
.catch(error => {
console.error(error);
})
.finally(() => {
stopLoader();
});
Promise.all()
&
Promise.any()
Promise.all()
:
.all()
이 인자로 받는 모든 promise가 fulfilled일때, .all()
을 부른 Promise 또한 fulfilled 상태가 되고, 그 외에는 reject 상태가 된다. Promise.all([promise1, promise2]).then(values => {
console.log(values);
}).catch(error => {
console.error(error);
});
Promise.any()
:
.all()
과 사용법이 비슷하지만, 인자로 받은 모든 promise가 아니라 그 중 하나의 promise라도 성공하면 가장 처음 성공하는 promise의 data를 받아온다.Promise.any([promise1, promise2]).then(value => {
console.log(value);
}).catch(error => {
console.error(error);
});