Wat is Async Code?
Asynchrone code is code die niet meteen klaar is. Denk aan:
- Data ophalen van een API
- Bestanden inladen
- Wachten op gebruikersinput
Voorbeeld van het gedrag
console.log('1. Start');
// Simuleer een API call van 2 seconden
setTimeout(() => {
console.log('2. Data opgehaald');
}, 2000);
console.log('3. Einde');
// Output:
// 1. Start
// 3. Einde
// 2. Data opgehaald (2 seconden later)
- JavaScript wacht NIET op setTimeout
- Regel 3 wordt meteen uitgevoerd
- Pas na 2 seconden komt de setTimeout callback
Het probleem met async code
Je wilt data ophalen en daarna iets ermee doen, maar JavaScript is al verder gegaan.
Probleem voorbeeld
let gebruiker = null;
// Haal gebruiker op (duurt 2 seconden)
setTimeout(() => {
gebruiker = { naam: 'Jan', leeftijd: 25 };
}, 2000);
// Probeer gebruiker te tonen:
console.log(gebruiker.naam); // ❌ ERROR - gebruiker is nog null
gebruiker.naam te lezen voordat de data geladen is.
Waarom is dit lastig?
Bij fetch(), API calls en database queries weet je niet precies hoelang het duurt. Het kan 100ms zijn, maar ook 5 seconden.
Promises
Een Promise is een “belofte” dat er later een resultaat komt. Een Promise heeft 3 states:
- pending – bezig / nog niet klaar
- fulfilled – gelukt (resultaat beschikbaar)
- rejected – mislukt (error)
Promise met .then()
fetch('./data.json')
.then(response => response.json()) // wacht op response
.then(data => { // wacht op JSON
console.log(data); // nu is data er
})
.catch(error => { // als er iets misgaat
console.error(error);
});
fetch()geeft een Promise terug.then()wordt uitgevoerd als de Promise klaar is- Je kunt meerdere
.then()achter elkaar gebruiken .catch()vangt fouten op
Callback hell
Met alleen .then() kan je code erg genest en onleesbaar worden.
fetch('./users.json')
.then(r => r.json())
.then(users => {
fetch('./posts.json')
.then(r => r.json())
.then(posts => {
fetch('./comments.json')
.then(r => r.json())
.then(comments => {
// heel veel nesting...
});
});
});
Async/Await
Async/await is een moderne manier om met Promises te werken. Het lijkt op “normale” synchrone code.
- Leesbaarder
- Minder nesting
- Makkelijker te debuggen
Basis syntax
// 1. async functie
async function haalDataOp() {
// 2. wacht op fetch
const response = await fetch('./data.json');
// 3. wacht op het omzetten naar JSON
const data = await response.json();
console.log(data); // nu is data er
}
// 4. functie aanroepen
haalDataOp();
asyncvoor de functie => deze functie kanawaitgebruikenawait=> wacht tot de Promise klaar is- Je mag
awaitalleen binnen eenasyncfunctie gebruiken
.then() versus async/await
Met .then():
function haalDataOp() {
fetch('./data.json')
.then(response => response.json())
.then(data => {
console.log(data);
});
}
Met async/await:
async function haalDataOp() {
const response = await fetch('./data.json');
const data = await response.json();
console.log(data);
}
Arrow functie met async
const haalDataOp = async () => {
const response = await fetch('./data.json');
const data = await response.json();
console.log(data);
};
haalDataOp();
Error handling met try/catch
Bij async/await gebruik je try/catch om fouten af te vangen.
async function haalDataOp() {
try {
const response = await fetch('./data.json');
if (!response.ok) {
throw new Error('Data niet gevonden');
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Er ging iets mis:', error);
}
}
haalDataOp();
try– probeer deze code uit te voerencatch– als er een error is, kom je hier terechtthrow new Error()– zelf een error gooien
.then() versus async/await error handling
Met .then():
fetch('./data.json')
.then(r => r.json())
.then(data => console.log(data))
.catch(error => console.error(error));
Met async/await:
async function haalDataOp() {
try {
const response = await fetch('./data.json');
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
Praktische voorbeelden
1. Gebruiker ophalen en tonen
async function toonGebruiker() {
try {
const response = await fetch('./user.json');
const gebruiker = await response.json();
document.querySelector('#naam').textContent = gebruiker.naam;
document.querySelector('#email').textContent = gebruiker.email;
} catch (error) {
console.error('Fout bij laden gebruiker:', error);
document.querySelector('#naam').textContent = 'Fout bij laden';
}
}
toonGebruiker();
2. Meerdere calls na elkaar (afhankelijk van elkaar)
async function haalAllesOp() {
try {
const gebruikerResponse = await fetch('./user.json');
const gebruiker = await gebruikerResponse.json();
const postsResponse = await fetch(`./posts/${gebruiker.id}.json`);
const posts = await postsResponse.json();
const commentsResponse = await fetch(`./comments/${posts[0].id}.json`);
const comments = await commentsResponse.json();
console.log(gebruiker, posts, comments);
} catch (error) {
console.error('Error:', error);
}
}
haalAllesOp();
.then() callbacks.
3. Meerdere calls tegelijk met Promise.all()
async function haalAllesTegelijkOp() {
try {
const [gebruiker, posts, comments] = await Promise.all([
fetch('./user.json').then(r => r.json()),
fetch('./posts.json').then(r => r.json()),
fetch('./comments.json').then(r => r.json())
]);
console.log('Alles geladen:', gebruiker, posts, comments);
} catch (error) {
console.error('Error:', error);
}
}
haalAllesTegelijkOp();
4. Data tonen op de pagina
async function toonProducten() {
const container = document.querySelector('#producten');
try {
container.innerHTML = '<p>Producten laden...</p>';
const response = await fetch('./producten.json');
const producten = await response.json();
let html = '';
for (let product of producten) {
html += `
<div class="product">
<h3>${product.naam}</h3>
<p>Prijs: €${product.prijs}</p>
</div>
`;
}
container.innerHTML = html;
} catch (error) {
console.error('Error:', error);
container.innerHTML = '<p>Fout bij laden van producten</p>';
}
}
document.addEventListener('DOMContentLoaded', toonProducten);
5. Formulier data versturen
async function verstuurFormulier(event) {
event.preventDefault();
const naam = document.querySelector('#naam').value;
const email = document.querySelector('#email').value;
try {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ naam, email })
});
if (!response.ok) {
throw new Error('Verzenden mislukt');
}
const result = await response.json();
console.log(result);
alert('Succesvol verstuurd!');
} catch (error) {
console.error('Error:', error);
alert('Er ging iets mis bij het versturen');
}
}
document.querySelector('#mijnForm')
.addEventListener('submit', verstuurFormulier);
Samenvatting
| Concept | Wat doet het? | Gebruik je het voor... |
|---|---|---|
async |
Maakt een functie asynchroon | Functies die await gebruiken |
await |
Wacht op een Promise | fetch, API calls, timeouts, etc. |
try/catch |
Fouten afvangen | Async/await code veilig maken |
Promise.all() |
Meerdere Promises tegelijk | Sneller meerdere requests doen |
Gebruik async/await
Leesbaarder dan lange .then() chains
Altijd try/catch
Vang fouten netjes op
Check response.ok
Controleer of je request gelukt is
Toon loading state
Laat de gebruiker zien dat er geladen wordt
Gebruik Promise.all
Voor parallelle requests
Log veel
Gebruik console.log om te zien wat er gebeurt
Cheat sheet template
async function mijnFunctie() {
try {
const response = await fetch('./data.json');
if (!response.ok) {
throw new Error('Fout bij ophalen');
}
const data = await response.json();
// Werk met data...
console.log(data);
} catch (error) {
console.error('Error:', error);
}
}
mijnFunctie();