Async / await



Async / await

av Ole Petter den 7. mars 2020

Sist oppdatert: 19 april, 2020 kl 11:19

Async / 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;
TMDB-api
Resultatet fra kallet i json-format

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>`
}))
1 Kommentarer
Suzy Miska

tҺe website іѕ really good, I like your website!

Legg igjen en kommentar