비동기를 처리하는 3가지 방법
1. Callback 함수
showFirst(function(result) {
showSecond(result, function(nextResult) {
showThird(nextResult, function(finalResult) {
console.log('the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
문제점
1) 가독성이 매우 떨어진다. (콜백지옥)
2) 복잡해지는 에러처리.
- 각 콜백함수에서 에러 핸들링을 해주어야한다. 에러처리를 하지 않으면 콜백함수 호출시, 어디서 에러가 발생한지 알기 어렵다.
2. Promise 객체
Promise를 사용하여 비동기 작업의 성공 또는 실패의 결과 값을 반환합니다.
결과 값을 받아 이후 처리를 컨트롤 할 수 있다.
Promise의 상태 값
Promise 객체는 new 키워드로 생성하고, 4개의 상태 값을 가집니다.
상태값은 크게 Pending과 Settled로 나누며,
Settled은 다시 fulfilled과 Rejected로 나뉜다.
Pending: 아직 결과 값이 반환되지 않은 진행 중인 상태 fulfilled: 성공 Rejected: 실패 Settled: 결과 값이 성공 혹은 실패로 반환된 상태 |
+ Settled된 값은 재실행 될 수 없다.
Promise 생성
1. 함수를 인자로 받는다.
2. 인자로 들어온 함수는 다시 resolve와 reject 2개의 함수를 인자로 받는다.
const promise = new Promise(function(res, rej) {
setTimeout(function() {
res(111);
}, 1000);
});
// arrow functiion
cosnt promise = new Promise((res, rej) => {
setTimeout(() => {
res(111);
}, 1000);
});
+ new Promise로 생성된 인스턴스 객체는 '객체'이기 때문에 위와 같이 변수로 할당하거나 함수의 인자로 사용할 수 있다.
Promise 사용
인스턴스 호출시, 대표 메소드 then과 catch
resolve -> then
resolve되는 값은 then 메소드의 인자로 넘어간다.
const promise = new Promise((res, rej) => {
setTimeout(() => {
res(111);
}, 1000);
});
promise
.then(res => console.log(res));
// 출력값
111
reject -> catch
reject 값은 catch 메소드로의 인자로 넘어가서 에러를 핸들링한다.
const promise = new Promise((res, rej) => {
setTimeout(() => {
rej('error!');
}, 1000);
});
promise
.then(res => console.log(res))
.catch(err => console.error(err));
// catch 메소드에 잡혀서 console.error에서 출력된 값
error!
point
then 메소드는 Promise를 다시 반환.
Promise 객체 반환 -> then, catch 메소드를 사용가능 -> 연속적인 then 메소드 사용 -> Promise chaining
showFirst() // showFirst 반환 값은 then 함수의 인자로 전달.
.then(res => showSecond(result)) // showSecond 반환 값도 then의 인자로 전달
.then(res => showThird(nextResult)) // showThird 반환 값도 then의 인자로 전달
.then(res => console.log(`the final result: ${finalResult}`))
.catch(err => console.error(err));
// 위의 Promise 객체들 중 하나라도 에러가 발생하면 catch 메소드로 넘겨진다.
catch 이후에도 chaining 가능
new Promise((res, rej) => {
console.log('Initial');
res(); // resolve된 후 then 실행
})
.then(() => {
throw new Error('Something failed');
console.log('Do this'); // error 발생으로 실행되지 않는다.
})
.catch(err => {
console.log(err); // throw new Error의 인자 값이 넘어온자.
})
.then(() => {
console.log('Do this, whatever happened before'); // catch 구문 이후 chaining
});
// 출력값
Initial
Something failed // ERROR
Do this, whatever happened before // catch 메소드 이후 then 메소드 실행
Promise.all
The Promise.all() method takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises. This returned promise will resolve when all of the input's promises have resolved, or if the input iterable contains no promises. It rejects immediately upon any of the input promises rejecting or non-promises throwing an error, and will reject with this first rejection message / error. - MDN
Promise.all 메소드는 배열로된 여러개의 프로미스들을 인자로 받아, 단 하나의 프로미스로 반환한다.
이 반환된 단일 프로미스는 배열에 담긴 프로미스들이 모두 resolve 되거나 더 이상 프로미스가 없을 때 resolve된다.
이들 프로미스 중 하나가 reject하거나 non-promise의 경우 바로 에러메세지를 보낸다.
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
3. async/ await
callback 함수와, promise의 단점을 보완한 async / await.
이 방법은 비동기적인 코드를 작성된 순서 그대로 실행되게 해줍니다.
async 함수
async function f() {
return 1;
}
function 앞에 async 키워드가 붙으면 해당 함수는 항상 Promise를 반환합니다.
Promise가 아닌 값을 반환하더라도 이행 상태의 Promise(resolved promise)로 감싸 이행된 Promise가 반환됩니다.
2) 예시는 명시적으로 Promise를 반환한 것이지만 1) 번째와 결과가 같습니다.
// 1)
async function f() {
return 1;
}
f().then(alert); // 1
// 2)
async function f() {
return Promise.resolve(1);
}
f().then(alert); // 1
Point
async가 붙은 함수는 반드시 프라미스를 반환하고, 프라미스가 아닌 것은 프라미스로 감싸 반환합니다.
await
await 키워드는 async 함수 안에서만 동작합니다.
말그대로 Promise가 처리될 때까지 함수 실행을 기다리게 만듭니다.
즉, 자바스크립트가 await 키워드를 만나면 프라미스가 처리(settled)될 때까지 기다린 후
그 결과를 반환합니다.
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("완료!"), 1000)
});
let result = await promise; // 프라미스가 이행될 때까지 기다림 (*)
alert(result); // "완료!"
}
f();
f함수를 호출하고, 함수가 본문이 실행되다가 (*) 부분에서 실행이 중단되고 Promise가 처리되면 실행이 재개됩니다.
이 때 Promise 객체의 반환값이 result 변수에 할당된다. 즉, 위 예시는 실행 1초 뒤에 '완료!'가 출력된다.
+ Promise 처리를 기다리는 동안 엔진이 다른 일(다른 스크립트 실행, 이벤트 처리 등)을 하기 때문에
CPU 리소스가 낭비되지 않는다.
Ref
ko.javascript.info/async-await
velog.io/@yejinh/%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0
'프론트엔드 > Javascript' 카테고리의 다른 글
이벤트 버블링, 캡쳐링, 위임 (0) | 2020.10.21 |
---|---|
자바스크립트의 동시성을 지원하는 이벤트루프 (0) | 2020.10.21 |
싱글스레드 자바스크립트 (0) | 2020.10.16 |
Class vs Object vs Instance 정리 (0) | 2020.10.10 |
자바스크립트 this (0) | 2020.09.26 |