try…catch로 에러 핸들링
try {
let y = 1;
const x = 2;
y = 3;
} catch (err) {
alert(err.message);
}
- try 블록 안에서 발생한 에러를 핸들링할 코드를 catch 블록 안에 작성해주면 된다.
Async/Await
const getPosition = function () {
return new Promise(function (resolve, reject) {
navigator.geolocation.getCurrentPosition(resolve, reject);
});
};
const whereAmI = async function () {
try {
// Geolocation
const pos = await getPosition();
const { latitude: lat, longitude: lng } = pos.coords;
// Reverse geocoding
const resGeo = await fetch(`https://geocode.xyz/${lat},${lng}?geoit=json`);
if (!resGeo.ok) throw new Error('Problem getting location data');
const dataGeo = await resGeo.json();
console.log(dataGeo);
// Country data
const res = await fetch(
`https://restcountries.com/v3.1/name/${dataGeo.country}`
);
if (!res.ok) throw new Error('Problem getting country');
const data = await res.json();
console.log(data);
renderCountry(data[0]);
} catch (err) {
console.error(`${err} 💥`);
renderError(`💥 ${err.message}`);
}
};
whereAmI();
whereAmI();
whereAmI();
console.log('FIRST');
- Promise 소비 코드를 조금 더 효율적으로 작성하기 위해 Async/Await을 사용할 수 있다.
- async 키워드를 사용해서 함수를 작성하면 해당 함수는 백그라운드에서 실행되고, 완료되면 프로미스를 리턴한다.
- async 안에 await 키워드를 사용하고 코드를 작성할 경우 프로미스가 fulfilled 상태가 되기 전에는 실행되지 않는다.
- async 함수 전체 코드는 백그라운드에서 실행되기 때문에 메인 스레드를 블로킹하지는 않고, 내부에서 순차적으로 await 코드가 처리된다.
- 프로미스에 then 메소드로 체이닝을 하는 것과 같은 원리로 동작하지만 코드를 읽기가 더 쉽다.
Async 함수로 값 리턴하기
const getJSON = function (url, errorMsg = 'Something went wrong') {
return fetch(url).then(response => {
if (!response.ok) throw new Error(`${errorMsg} (${response.status})`);
return response.json();
});
};
const getPosition = function () {
return new Promise(function (resolve, reject) {
navigator.geolocation.getCurrentPosition(resolve, reject);
});
};
const whereAmI = async function () {
try {
// Geolocation
const pos = await getPosition();
const { latitude: lat, longitude: lng } = pos.coords;
// Reverse geocoding
const resGeo = await fetch(`https://geocode.xyz/${lat},${lng}?geoit=json`);
if (!resGeo.ok) throw new Error('Problem getting location data');
const dataGeo = await resGeo.json();
// Country data
const res = await fetch(
`https://restcountries.com/v3.1/name/${dataGeo.country}`
);
if (!resGeo.ok) throw new Error('Problem getting country');
const data = await res.json();
renderCountry(data[0]);
return `You are in ${dataGeo.city}, ${dataGeo.country}`;
} catch (err) {
console.error(`${err} 💥`);
renderError(`💥 ${err.message}`);
// Reject promise returned from async function
throw err;
}
};
console.log('1: Will get location');
// const city = whereAmI(); // 프로미스를 리턴함
// console.log(city);
// whereAmI()
// .then(city => console.log(`2: ${city}`))
// .catch(err => console.error(`2: ${err.message} 💥`))
// .finally(() => console.log('3: Finished getting location'));
(async function () {
try {
const city = await whereAmI();
console.log(`2: ${city}`);
} catch (err) {
console.error(`2: ${err.message} 💥`);
}
console.log('3: Finished getting location');
})();
- async 함수는 프로미스를 리턴하기 때문에 단순히 값을 사용할 수 없다.
- then 메소드를 사용해도 되나, async 함수 안에서 await 키워드로 받아서 사용하는 것이 조금 더 코드 가독성이 높다.
- 실제 개발하면서도 async 안에서 async를 사용하는 코드를 작성할 일이 많을 것이다.
- 또한 async 함수에서 에러가 발생하여서 정상적인 값을 반환받지 못했을 때에 대비한 코드를 작성해야 한다.
Promise 병렬 실행 콤비네이터: all
const getJSON = function (url, errorMsg = 'Something went wrong') {
return fetch(url).then(response => {
if (!response.ok) throw new Error(`${errorMsg} (${response.status})`);
return response.json();
});
};
const get3Countries = async function (c1, c2, c3) {
try {
// const [data1] = await getJSON(
// `https://restcountries.com/v3.1/name/${c1}`
// );
// const [data2] = await getJSON(
// `https://restcountries.com/v3.1/name/${c2}`
// );
// const [data3] = await getJSON(
// `https://restcountries.com/v3.1/name/${c3}`
// );
// console.log([data1.capital, data2.capital, data3.capital]);
const data = await Promise.all([
getJSON(`https://restcountries.com/v3.1/name/${c1}`),
getJSON(`https://restcountries.com/v3.1/name/${c2}`),
getJSON(`https://restcountries.com/v3.1/name/${c3}`),
]);
console.log(data.map(d => d[0].capital));
} catch (err) {
console.error(err);
}
};
get3Countries('portugal', 'canada', 'tanzania');
- Promise.all을 사용하면 비동기 함수가 병렬로 실행된다.
다른 콤비네이터: race, allSettled, any
(async function () {
const res = await Promise.race([
getJSON(`https://restcountries.com/v3.1/name/italy`),
getJSON(`https://restcountries.com/v3.1/name/egypt`),
getJSON(`https://restcountries.com/v3.1/name/mexico`),
]);
console.log(res[0]);
})();
const timeout = function (sec) {
return new Promise(function (_, reject) {
setTimeout(function () {
reject(new Error('Request took too long!'));
}, sec * 1000);
});
};
Promise.race([
getJSON(`https://restcountries.com/v3.1/name/tanzania`),
timeout(5),
])
.then(res => console.log(res[0]))
.catch(err => console.error(err));
- race는 말 그대로 여러 코드 중 가장 먼저 fulfilled 상태로 리턴된 프로미스를 반환하는 기능이다.
- race는 타임아웃을 걸어야할 때 많이 사용하기도 한다.
Promise.allSettled([
Promise.resolve('Success'),
Promise.reject('ERROR'),
Promise.resolve('Another success'),
]).then(res => console.log(res));
Promise.all([
Promise.resolve('Success'),
Promise.reject('ERROR'),
Promise.resolve('Another success'),
])
.then(res => console.log(res))
.catch(err => console.error(err));
- allSettled는 rejected 상태의 프로미스가 있어도 모든 결과를 배열로 반환한다. 반면 all은 rejected된 프로미스가 있으면 에러가 발생한다.
Promise.any([
Promise.resolve('Success'),
Promise.reject('ERROR'),
Promise.resolve('Another success'),
])
.then(res => console.log(res))
.catch(err => console.error(err));
- any의 경우 가장 먼저 fulfilled 상태로 반환된 프로미스를 하나만 리턴한다.
- 모두 실패하면 AggregateError: All promises were rejected 에러가 발생한다.
Related