Async/Await
보기에는 동기적인 것처럼 보이나 사실 behind the scene에서는 비동기적으로 작동한다.
Async와 Await는 promise안에 있는 method위에 뿌려진 syntactic sugar!
await 뒤에는 promise가 나온다.
promise(fetch, json 등 등) 앞에 await를 붙히고 변수에 저장하는 로직
whereAmI 함수 async function으로 만들기
const getPosition = function () {
return new Promise(function (resolve, reject) {
navigator.geolocation.getCurrentPosition(resolve, reject);
});
};
fetch(`https://restcountries.com/v2/name/${country}`).then(res => console.log(res))
const whereAmI = async function () {
//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`);
const dataGeo = await resGeo.json();
console.log(dataGeo);
//Country Data
const res = await fetch(
`https://restcountries.com/v2/name/${dataGeo.country}`
);
console.log(res);
const data = await res.json();
renderCountry(data[0]);
};
whereAmI();
console.log('FIRST');
FIRST 가 먼저 콘솔에 출력된다. why? whereAmI는 비동기
// Coding challenge 3// let currentImage;
const wait = function (seconds) {
return new Promise(function (resolve) {
setTimeout(resolve, seconds * 1000);
});
};
const imagesContainer = document.querySelector('.images');
const createImage = function (imgPath) {
return new Promise(function (resolve, reject) {
const img = document.createElement('img');
img.src = imgPath;
img.addEventListener('load', () => {
imagesContainer.appendChild(img);
resolve(img);
});
img.addEventListener('error', err => {
reject(new Error('Image not found'));
});
});
};
기본 형태
try {
let y = 1;
const x = 2;
y = 3;
} catch (err) {
alert(err.message);
}
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/v2/name/${dataGeo.country}`
);
if (!resGeo.ok) throw new Error('Problem getting country data');
const data = await res.json();
renderCountry(data[0]);
return `You are in ${dataGeo.city}, ${dataGeo.country}`;
} catch (err) {
console.error(`${err.message} happened`);
renderError(`💥 ${err.message}`);
//Reject promise returned from async function
throw err; // err를 throw해줌으로써 아래 then 다음의 코드를 reject로 인식한다.
}
};
console.log('1 : I will get location');
const city = whereAmI();
console.log(city); //Promise {<pending>} => aysnc function 항상 promise를 return 한다.
//변수안에 저장을 하더라도 string value가 return되지 않음! string value는 해당 primise의 fulfilled value 가 될 것!
fullfilled value 얻는 법
whereAmI()
.then(city => console.log(city))
.catch(err => console.error(`2 : ${err.message}`))
.finally(() => console.log('3 : Finished getting location'));
(async function () {
try {
const city = await whereAmI();
console.log(city);
} catch (err) {
console.error(`2 : ${err.message}`);
}
console.log('3 : Finished getting location');
})();
하나의 promise reject되면 전체 promise가 reject된다.
combinator function 이라고 불리기도 한다. multiple functions를 combine 하므로.
const get3Countries = async function (c1, c2, c3) {
try {
// const [data1] = await getJSON(`https://restcountries.com/v2/name/${c1}`);
// const [data2] = await getJSON(`https://restcountries.com/v2/name/${c2}`);
// const [data3] = await getJSON(`https://restcountries.com/v2/name/${c3}`);
//병렬적으로 다운로드 받기! Promis.all([promise1, promise2, promise3])
const data = await Promise.all([
getJSON(`https://restcountries.com/v2/name/${c1}`),
getJSON(`https://restcountries.com/v2/name/${c2}`),
getJSON(`https://restcountries.com/v2/name/${c3}`),
]);
console.log(data.map(d => d[0].capital));
} catch (err) {
console.error(err);
}
};
get3Countries('portugal', 'usa', 'india');
array of promises를 받고 가장빨리 settled된 promise를 return 한다.
(async function () {
const res = await Promise.race([
getJSON(`https://restcountries.com/v2/name/italy`),
getJSON(`https://restcountries.com/v2/name/egypt`),
getJSON(`https://restcountries.com/v2/name/portugal`),
]);
console.log(res[0]); //italy
})();
const timeout = function (sec) {
return new Promise(function (_, reject) {
setTimeout(() => {
reject(new Error('Request took too long!'));
}, sec * 1000);
});
};
Promise.race([getJSON(`https://restcountries.com/v2/name/italy`), timeout(1)])
.then(res => console.log(res[0]))
.catch(err => console.error(err));
모든 promise의 result들을 return 한다. (reject 경우도 포함해서)
Promise.allSettled([
Promise.resolve('Success'),
Promise.reject('ERROR'),
Promise.resolve('Another success'),
])
.then(res => console.log(res))
.catch(err => console.errror(err));
first fulfilled promise를 return한다. reject promise는 무시한다.
Promise.any([
Promise.resolve('Success'),
Promise.reject('ERROR'),
Promise.resolve('Another success'),
])
.then(res => console.log(res))
.catch(err => console.errror(err));
// Success
const wait = function (seconds) {
return new Promise(function (resolve) {
setTimeout(resolve, seconds * 1000);
});
};
const imagesContainer = document.querySelector('.images');
const createImage = function (imgPath) {
return new Promise(function (resolve, reject) {
const img = document.createElement('img');
img.src = imgPath;
img.addEventListener('load', () => {
imagesContainer.appendChild(img);
resolve(img);
});
img.addEventListener('error', err => {
reject(new Error('Image not found'));
});
});
};
createImage('img/img-1.jpg')
.then(img => {
currentImage = img;
return wait(2);
})
.then(() => {
currentImage.style.display = 'none';
return createImage('img/img-2.jpg');
})
.then(img => {
currentImage = img;
return wait(2);
})
.then(() => (currentImage.style.display = 'none'))
.catch(err => console.error(err));
Part 1
위의 promise를 async function으로 만들기
const loadNPause = async function () {
try {
// load image1
let img = await createImage('img/img-1.jpg');
await wait(2);
img.style.display = 'none';
// load image2
img = await createImage('img/img-2.jpg');
await wait(2);
img.style.display = 'none';
} catch (err) {
console.error(err);
}
};
//loadNPause();
Part 2
유의할 포인트! async 함수는 항상 promise를 return한다!
fullfilled value를 얻고 싶다면 await 뒤에 적은 뒤 변수로 묶어줄 것
ex) const imgs = imgArr.map(async img => await console.log(img)) => promise 배열
const loadAll = async function (imgArr) {
try {
const imgs = imgArr.map(async img => await createImage(img));
const imgsEl = await Promise.all(imgs);
imgsEl.forEach(img => img.classList.add('parallel'));
} catch (err) {
console.error(err);
}
};
loadAll(['img/img-1.jpg', 'img/img-2.jpg', 'img/img-3.jpg']);