Async / await
Async / await
av Ole Petter den 7. mars 2020
Sist oppdatert: 19 april, 2020 kl 11:19Async / await er en metode som brukes til å hente data fra eksterne API-er. Den er ikke-blokkerende, det betyr at andre operasjoner kan foregå i bakgrunnen mens dataene hentes fra en API.
MDN har en god artikkel om async await på deres side:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
I dette eksempelet skal jeg bruke The Movie Database til å hente de mest populære filmene akkurat nå, og vise de på en nettside.
Contents
Sette opp app.js og index.html
For å komme igang lager jeg en index.html side og en app.js fil. Disse to brukes til å henholdsvis vise de nyeste filmene, og hente filmene fra en ekstern side som inneholder JSON-data.
const url = 'https://api.themoviedb.org/3/movie/popular?api_key=<DIN_NØKKEL>;
const getMovies = async() => {
const response = await fetch(url);
const data = await response.json();
const dataresults = data.results;
return dataresults;
}
Først lagrer jeg api-adressen i en konstant kalt «url». For å hente ut dataene bruker jeg en metode kalt «fetch», men først må jeg kalle async() for at kallet på den eksterne api-en ikke skal blokkere resten av koden.
«const response» er variabelen som henter dataene fra fetch(url), og dataen i denne variabelen er i json-format. For at dataene skal kunne brukes i html-format, må det brukes en funksjon kalt json() på denne variabelen.
const data = await response.json();
Når dataene er konvertert, kan de returneres fra funksjonen. I første omgang er «const data» kun et objekt, og for å gjøre det enklere å bruke disse dataene aksesserer jeg resultatene i objektet for så å returnere dataene fra funksjonen.
const dataresults = data.results;
Man kan bruke ulike verktøy for å enkelt få oversikt over responsen fra et API-kall. Postman er et godt alternativ, men man kan også bruke nettleseren. Firefox styler automatisk json-dataene slik at de er oversiktlig, mens man i Chrome kan laste ned utvidelser som gjør det samme.
På bildet ovenfor ser man at man først får et objekt, og for å få tilgang til selve tabellen med dataene må man gå inn på «results», som er tabellen med hver enkelt film.
Vise filmene på index.html
For å vise filmene man henter fra api-kallet kan man opprette en div med en id, for eksempel «movies».
Deretter kan man bruke denne id-en til å sette inn html innenfor dette elementet.
Først oppretter jeg en konstant kalt «moviesDiv», som brukes til å sette inn html-kode for hver enkelt film jeg henter fra TMDB.
index.html:
<div class="container">
<h1>Film</h1>
<div class="row" id="movies"></div>
</div>
app.js:
const moviesDiv = document.getElementById('movies');
// Bruker template literal ``//
getMovies().then((data => {
moviesDiv.innerHTML = `
<div class="row">
${data.map(movie => `
<div class="col-md-3">
<p>${movie.title}</p>
<img class="img-fluid" src="https://image.tmdb.org/t/p/w1280${movie.poster_path}">
</div>
`).join(' ') }
</div>`
}))
En template literal er en ny metode i ES6 og nyere for å skrive javascript-kode inne i html-kode. For å bruke javascript-variabler og funksjoner inne i en template literal, skriver man først: ${..kode..}.
I eksempelet ovenfor fyller jeg for eksempel inn tittelen på filmen ved å skrive: ${movie.title} . Før ES6/ES2015 måtte man konkatenere tekststrenger med en » fulgt av + og så javascript-koden. Eksempel:
// Gammel syntaks
"<h1>" + movie.title + "</h1>";
// Ny syntaks
`<h1>${movie.title}</h1>`;
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
Resultat
Etter at koden er fylt ut i app.js og referert til i index.html kan jeg vise filmene som er hentet fra API-kallet på hovedsiden index.html.
API-kallet er inndelt i sider, og man viser kun 20 filmer per side. Derfor vises kun 20 filmer som standard. Man kan legge til javascript-funksjoner for å navigere sidene, men det får demonstreres i et senere innlegg.
Bruke templating engines
For å generere sider kan man installere en utvidelse kalt ‘ejs’. Dette er en templating engine som genererer sider slik at man kan skrive normal html kode, og inkludere variabler i koden ved hjelp av innebygd syntaks.
Andre alternativer er blant annet handlebars og pug, som også er veldig populære. Pug er annerledes fordi den har en forkortet versjon av html-kode som gjør det kjappere å lage html-maler, men det krever en viss tilvenning å bruke.
Kildekode
index.html
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<title>TMDB</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<div class="container">
<h1>Film</h1>
<div class="row" id="movies"></div>
</div>
<!-- paginering - ikke lagt til funksjoner enda -->
<input type="hidden" id="page" value="1">
<div class="d-flex justify-content-center mt-4">
<nav aria-label="Page navigation example">
<ul class="pagination">
<li class="page-item"><a class="page-link" href="">Previous</a></li>
<li class="page-item"><a class="page-link">1</a></li>
<li class="page-item"><a class="page-link" href="?page=2">2</a></li>
<li class="page-item"><a class="page-link" href="?page=3">3</a></li>
<li class="page-item"><button onclick="nextPage();" class="page-link">Next</button ></li>
</ul>
</nav>
</div>
<!-- paginering slutt -->
<script src="app.js"></script>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>
app.js
let page = document.getElementById('page').value;
function nextPage() {
//page = 2;
page = document.getElementById('page').value = 2;
console.log(page)
return page;
}
const url = 'https://api.themoviedb.org/3/movie/popular?api_key=<DIN_NØKKEL_HER>&page=' + page;
const getMovies = async() => {
const response = await fetch(url);
const data = await response.json();
const dataresults = data.results;
return dataresults;
}
const moviesDiv = document.getElementById('movies');
getMovies().then((data => {
moviesDiv.innerHTML = `
<div class="row">
${data.map(movie => `
<div class="col-md-3">
<p>${movie.title}</p>
<img class="img-fluid" src="https://image.tmdb.org/t/p/w1280${movie.poster_path}">
</div>
`).join(' ') }
</div>`
}))
Suzy Miska
tҺe website іѕ really good, I like your website!