A fetch() function can be written with Async/Await as stand-alone version:
asyncfunctionfetchFunction(){const response =awaitfetch(url);if(!response.ok){thrownewError(`An error has occurred: ${response.status}${response.statusText}`);// check for errors}return response.json();}asyncfunctionotherFunction(){try{const data =awaitfetchFunction();// process the data inside this function// ...}catch(error){
console.error(error);}}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Or as a function where you do something with the data inside te function itself:
asyncfunctionfetchFunction(){try{const response =awaitfetch(url);if(!response.ok){thrownewError(`An error has occurred: ${response.status}${response.statusText}`);// check for errors}const data =await response.json();// process the data inside this function// ...}catch(error){
console.error(error);}}
Open es6/asyncAwait/calculator.html and es6/asyncAwait/calculator.js
Compare the refactored code with the code from es6/promises/calculator.js
There are multiple then() handlers in this solution, but only line 16 and line 24 refers to a promise
The rest of them contains just normal (regular) functions
let x =5;constdelay=(ms =1000)=>{returnnewPromise((resolve, reject)=>{if(isNaN(ms)){reject(newError('Delay only except milliseconds'));}else{setTimeout(()=>resolve(`waited for ${ms} ms`), ms);}});};
console.log(`x = ${x}`);// step 1
console.warn('Give me two seconds, first empty my coffee and then I will multiply x by 2');delay(2000).then((data)=>{
console.log(`%c ${data}`,'color: blue');
x *=2;
console.log(`x * 2 = ${x}`);})// step 2.then(()=> console.warn("Give me a sec, I'm coming down and add 6 to x")).then(()=>delay())// 1000 is the default value.then((data)=>{
console.log(`%c ${data}`,'color: blue');
x +=6;
console.log(`x + 6 = ${x}`);}).then(()=>{// step 3
x -=1;
console.log(`x - 1 = ${x}`);// step 4 (output x to DOM)
document.querySelector('pre').innerText =`x = ${x}`;}).catch((error)=> console.error(error));
Line 15: prefix the function calculator() with the keyword async because it contains (two) references to a promise
Line 19 and line 25: prefix the promise delay() with the keyword await so the next lines of code have to wait until the promise is resolved
Place the resolved values in the variable data to use then later in the code
let x =5;constdelay=(ms =1000)=>{returnnewPromise((resolve, reject)=>{if(isNaN(ms)){reject(newError('Delay only except milliseconds'));}else{setTimeout(()=>resolve(`waited for ${ms} ms`), ms);}});};
console.log(`x = ${x}`);asyncfunctioncalculator(){try{// step 1
console.warn('Give me two seconds, first empty my coffee and then I will multiply x by 2');let data =awaitdelay(2000);
console.log(`%c ${data}`,'color: blue');
x *=2;
console.log(`x * 2 = ${x}`);// step 2
console.warn("Give me a sec, I'm coming down and add 6 to x");
data =awaitdelay();
console.log(`%c ${data}`,'color: blue');
x +=6;
console.log(`x + 6 = ${x}`);// step 3
x -=1;
console.log(`x - 1 = ${x}`);// step 4 (output x to DOM)
document.querySelector('pre').innerText =`x = ${x}`;}catch(error){
console.error(error);}}calculator();
Open es6/asyncAwait/karaoke.html and es6/asyncAwait/karaoke.js
Compare the refactored code with the code from es6/promises/karaoke.js
const lyrics = document.getElementById('lyrics');const heroes ={
line1:'<p><span>1</span> I, I will be king</p>',
line2:'<p><span>2</span> And you, you will be queen</p>',
line3:'<p><span>3</span> Though nothing will drive them away</p>',
line4:'<p><span>4</span> We can beat them, just for one day</p>',
line5:'<p><span>5</span> We can be heroes, just for one day</p>',};constdelay=(ms =2000)=>newPromise((resolve)=>setTimeout(resolve, ms));
lyrics.innerHTML +='<p>--- START --------------------------------------------</p>';delay().then(()=>{
lyrics.innerHTML += heroes.line1;returndelay();}).then(()=>{
lyrics.innerHTML += heroes.line2;returndelay();}).then(()=>{
lyrics.innerHTML += heroes.line3;returndelay();}).then(()=>{
lyrics.innerHTML += heroes.line4;returndelay();}).then(()=>{
lyrics.innerHTML += heroes.line5;returndelay();}).then(()=>{
lyrics.innerHTML +='<p>--- END ----------------------------------------------</p>';returndelay();}).then(()=> console.log('lyrics written to page'));
const karaoke = document.getElementById('lyrics');const heroes ={
line1:'<p><span>1</span> I, I will be king</p>',
line2:'<p><span>2</span> And you, you will be queen</p>',
line3:'<p><span>3</span> Though nothing will drive them away</p>',
line4:'<p><span>4</span> We can beat them, just for one day</p>',
line5:'<p><span>5</span> We can be heroes, just for one day</p>',};constdelay=(ms =2000)=>newPromise((resolve)=>setTimeout(resolve, ms));asyncfunctionaddLine(){
karaoke.innerHTML +='<p>--- START --------------------------------------------</p>';awaitdelay();
karaoke.innerHTML += heroes.line1;awaitdelay();
karaoke.innerHTML += heroes.line2;awaitdelay();
karaoke.innerHTML += heroes.line3;awaitdelay();
karaoke.innerHTML += heroes.line4;awaitdelay();
karaoke.innerHTML += heroes.line5;awaitdelay();
karaoke.innerHTML +='<p>--- END ----------------------------------------------</p>';
console.log('lyrics written to page');}addLine();
Open es6/asyncAwait/random_words.html and es6/asyncAwait/random_words.js
Compare the refactored code with the code from es6/promises/random_words.js
const number = document.getElementById('number');const dl = document.querySelector('dl');const wordUrl ='https://random-words-api.vercel.app/word';
number.addEventListener('change',()=>{
console.clear();
dl.innerHTML ='';const words =[];for(let i =1; i <= number.value; i++){// push the JSON response from the fetch API to the words[] array// remember that the JSON response is also a promise!
words.push(fetch(wordUrl).then((response)=> response.json()));}
Promise.all(words).then((responses)=>{// loop over all JSON responses once they have all been resolved
responses.forEach((response, index)=>{
console.log(`response ${index}`, response);
dl.innerHTML +=`<dt>${response[0].word}</dt><dd>${response[0].definition}</dd>`;});}).catch((error)=> console.error(error));});
number.dispatchEvent(newEvent('change'));
Open es6/asyncAwait/omdb.html and es6/asyncAwait/omdb.js
Compare the refactored code with the code from es6/fetch/omdb.js
const omdbapi ='https://www.omdbapi.com/';const spinner = document.querySelector('.spinner');const form = document.querySelector('form');functionfetchMovie(url){
console.log(url);fetch(url).then((response)=>{if(!response.ok){thrownewError(`An error has occurred: ${response.status}${response.statusText}`);// check for errors}return response.json();}).then((movie)=>{// info if movie not foundlet info =`
<div class="card warning full-width">
<p>No info found for <b>${title.value}</b></p>
</div>`;// overwrite info if the movie is foundif(movie.Response ==='True'){const poster = movie.Poster && movie.Poster.length >10?`<img src="${movie.Poster}">`:'';
info =`
<div class="row">
<div class="col-sm-6">${poster}</div>
<div class="col-sm-6">
<h2>${movie.Title}</h2>
<p><b>Genre: </b>${movie.Genre}<br>
<b>Released: </b>${movie.Released}<br>
<b>Actors: </b>${movie.Actors}<br>
<b>Director: </b>${movie.Director}<br></p>
<hr>
<p class="text-justify">${movie.Plot}</p>
</div>
</div>`;}
document.getElementById('movieContainer').innerHTML = info;}).then(()=>{
spinner.classList.add('hidden');}).catch((error)=>{
spinner.classList.add('hidden');
console.log(error);});}
form.addEventListener('submit',(e)=>{
e.preventDefault();// get all field data from the formconst data =newFormData(form);// convert data to a query stringconst queryString =newURLSearchParams(data).toString();// console.log(queryString);// fetch data from OMDbfetchMovie(`${omdbapi}?${queryString}`);});
form.dispatchEvent(newEvent('submit'));
const omdbapi ='https://www.omdbapi.com/';const spinner = document.querySelector('.spinner');const form = document.querySelector('form');functionupdatePage(movie){// info if movie not foundlet info =`
<div class="card warning full-width">
<p>No info found for <b>${title.value}</b></p>
</div>`;// overwrite info if the movie is foundif(movie.Response ==='True'){const poster = movie.Poster && movie.Poster.length >10?`<img src="${movie.Poster}">`:'';
info =`
<div class="row">
<div class="col-sm-6">${poster}</div>
<div class="col-sm-6">
<h2>${movie.Title}</h2>
<p><b>Genre: </b>${movie.Genre}<br>
<b>Released: </b>${movie.Released}<br>
<b>Actors: </b>${movie.Actors}<br>
<b>Director: </b>${movie.Director}<br></p>
<hr>
<p class="text-justify">${movie.Plot}</p>
</div>
</div>`;}
document.getElementById('movieContainer').innerHTML = info;}asyncfunctionfetchMovie(url){try{const response =awaitfetch(url);if(!response.ok){thrownewError(`An error has occurred: ${response.status}${response.statusText}`);// check for errors}const movie =await response.json();updatePage(movie);}catch(error){
console.error(error);}
spinner.classList.add('hidden');}
form.addEventListener('submit',(e)=>{
e.preventDefault();const data =newFormData(form);const queryString =newURLSearchParams(data).toString();
spinner.classList.remove('hidden');fetchMovie(`${omdbapi}?${queryString}`);});
form.dispatchEvent(newEvent('submit'));
Open es6/asyncAwait/irail.html and es6/asyncAwait/irail.js
Compare the refactored code with the code from es6/fetch/irail.js
const buttons = document.getElementById('buttons');const preloader = document.getElementById('preloader');const stationsUrl ='https://api.irail.be/stations/?format=json&lang=en';let closestStations =[];// default value for myLocation = Geelconst myLocation ={
lat:51.162074,
lng:4.99088,};// get current positionif(navigator.geolocation){
navigator.geolocation.getCurrentPosition((position)=>{// update myLocation
myLocation.lat = position.coords.latitude;
myLocation.lng = position.coords.longitude;// fetch all Belgian railway stationsfetchStations();},(error)=>{alert('Unable to retrieve your location');},{
enableHighAccuracy:true,
timeout:3000,});}else{alert('Geolocation is not supported by this browser');}functionfetchStations(){// fetch all Belgian railway stations
preloader.style.visibility ='visible';
preloader.querySelector('p').textContent ='Loading stations ...';fetch(stationsUrl).then((response)=>// return JSON part of the response
response.json()).then((stations)=>{
console.log('unordered list of railway stations', stations);
preloader.querySelector('p').textContent ='Find closest station ...';// modify the properties of every stationreturn stations.station.map((st)=>{// convert lat and lng form string to numberconst lat =+st.locationY;const lng =+st.locationX;// calculate the distance between your location and the station location as the crow flies (in km)const distance =calcCrow(lat, lng, myLocation.lat, myLocation.lng);return{
lat,
lng,
distance,
id: st.id,
name: st.name,};});}).then((stations)=>{// order railway stations by distance from your locationconst ordered = stations.sort((a, b)=> a.distance - b.distance);
console.log('ordered list of railway stations', ordered);return ordered;}).then((orderedStations)=>{// get the five closest railway stations
closestStations = orderedStations.slice(0,5);
console.table(closestStations);// add a button for every station
closestStations.forEach((station)=>{
buttons.innerHTML +=`<button data-id="${station.id}">${station.name}</button>`;});// add event listener to every button
buttons.querySelectorAll('button').forEach((button)=>{
button.addEventListener('click',function(e){const id =this.dataset.id;
document.getElementById('station').textContent =this.textContent;// get timetable from the clicked stationfetchTimetable(id,this.textContent);});});// trigger click event on first button
buttons.querySelector('button:first-child').dispatchEvent(newEvent('click'));
preloader.style.visibility ='hidden';}).catch((error)=>{
console.log(error);});}functionfetchTimetable(id, station){
preloader.style.visibility ='visible';
preloader.querySelector('p').textContent =`Loading timetable for ${station}...`;const liveboardUrl =`https://api.irail.be/liveboard/?id=${id}&format=json&lang=en`;fetch(liveboardUrl).then((response)=> response.json()).then((data)=>{// we only need the departure[] containing the timetableconst table = data.departures.departure;
console.log('timetable', table);// return the transformed timetablereturn table.map((tbl)=>{// the API sends the time in sec, we need msconst departure =newDate(+tbl.time *1000).toTimeString().substring(0,5);let delay ='';let color ='border-green';// if delay is not '0', draw a red bordeif(tbl.delay !=='0'){// convert the delay from sec to min
delay =`+${tbl.delay /60}`;
color ='border-red';}return{
to: tbl.station,
platform: tbl.platform,
delay,
color,
departure,};});}).then((table)=>{// build the timetablelet rows ='';
table.forEach((train)=>{
rows +=`
<div class="${train.color}">
<span>${train.departure}</span>
<span>${train.delay}</span>
<span>${train.platform}</span>
<span>${train.to}</span>
</div>
`;});
document.getElementById('timetable').innerHTML = rows;
preloader.style.visibility ='hidden';}).catch((error)=>alert(error));}//This function takes in latitude and longitude of two location and returns the distance between them as the crow flies (in km)functioncalcCrow(lat1, lon1, lat2, lon2){constR=6371;// kmconst dLat =((lat2 - lat1)* Math.PI)/180;const dLon =((lon2 - lon1)* Math.PI)/180;const latitude1 =(lat1 * Math.PI)/180;const latitude2 =(lat2 * Math.PI)/180;const a = Math.sin(dLat /2)* Math.sin(dLat /2)+ Math.sin(dLon /2)* Math.sin(dLon /2)* Math.cos(latitude1)* Math.cos(latitude2);const c =2* Math.atan2(Math.sqrt(a), Math.sqrt(1- a));return Math.round(R* c *100)/100;}