Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions 1-js/11-async/08-async-await/01-rewrite-async/solution.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

The notes are below the code:
Noterne er under koden:

```js run
async function loadJson(url) { // (1)
Expand All @@ -17,17 +17,17 @@ loadJson('https://javascript.info/no-such-user.json')
.catch(alert); // Error: 404 (4)
```

Notes:
Noter:

1. The function `loadJson` becomes `async`.
2. All `.then` inside are replaced with `await`.
3. We can `return response.json()` instead of awaiting for it, like this:
1. Funktionen `loadJson` bliver `async`.
2. Alle `.then` indeni erstattes med `await`.
3. Vi kan bruge `return response.json()` i stedet for at vente på det, som dette:

```js
if (response.status == 200) {
return response.json(); // (3)
}
```

Then the outer code would have to `await` for that promise to resolve. In our case it doesn't matter.
4. The error thrown from `loadJson` is handled by `.catch`. We can't use `await loadJson(…)` there, because we're not in an `async` function.
Den ydre kode vil være nødt til at vente med `await` på at det promise løses. I vores tilfælde spiller det ikke en rolle.
4. Fejlen kastet fra `loadJson` håndteres af `.catch`. Vi kan ikke bruge `await loadJson(…)` der, fordi vi ikke er i en `async` funktion.
4 changes: 2 additions & 2 deletions 1-js/11-async/08-async-await/01-rewrite-async/task.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

# Rewrite using async/await
# Omskriv ved brug af async/await

Rewrite this example code from the chapter <info:promise-chaining> using `async/await` instead of `.then/catch`:
Omskriv dette eksempelkode fra kapitlet <info:promise-chaining> ved hjælp af `async/await` i stedet for `.then/catch`:

```js run
function loadJson(url) {
Expand Down
16 changes: 8 additions & 8 deletions 1-js/11-async/08-async-await/02-rewrite-async-2/solution.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

There are no tricks here. Just replace `.catch` with `try..catch` inside `demoGithubUser` and add `async/await` where needed:
Der er ikke nogen tricks her. Bare erstat `.catch` med `try..catch` inde i `demoGithubUser` og tilføj `async/await` hvor det er nødvendigt:

```js run
class HttpError extends Error {
Expand All @@ -19,29 +19,29 @@ async function loadJson(url) {
}
}

// Ask for a user name until github returns a valid user
// Spørg efter et brugernavn indtil github returnerer en gyldig bruger
async function demoGithubUser() {

let user;
while(true) {
let name = prompt("Enter a name?", "iliakan");
let name = prompt("Skriv et brugernavn?", "iliakan");

try {
user = await loadJson(`https://api.github.com/users/${name}`);
break; // no error, exit loop
break; // ingen fejl, hop ud af loopet
} catch(err) {
if (err instanceof HttpError && err.response.status == 404) {
// loop continues after the alert
alert("No such user, please reenter.");
// loop fortsætter efter alert
alert("Brugeren findes ikke. Indtast et nyt brugernavn.");
} else {
// unknown error, rethrow
// ukendt fejl, rethrow
throw err;
}
}
}


alert(`Full name: ${user.name}.`);
alert(`Fulde navn: ${user.name}.`);
return user;
}

Expand Down
14 changes: 7 additions & 7 deletions 1-js/11-async/08-async-await/02-rewrite-async-2/task.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

# Rewrite "rethrow" with async/await
# Omskriv "rethrow" med async/await

Below you can find the "rethrow" example. Rewrite it using `async/await` instead of `.then/catch`.
Nedenfor ser du "rethrow" eksemplet. Omskriv det ved hjælp af `async/await` i stedet for `.then/catch`.

And get rid of the recursion in favour of a loop in `demoGithubUser`: with `async/await` that becomes easy to do.
Og erstat rekursionen med et loop i `demoGithubUser`: med `async/await` bliver det nemt at gøre.

```js run
class HttpError extends Error {
Expand All @@ -25,18 +25,18 @@ function loadJson(url) {
});
}

// Ask for a user name until github returns a valid user
// Spørg efter et brugernavn indtil github returnerer en gyldig bruger
function demoGithubUser() {
let name = prompt("Enter a name?", "iliakan");
let name = prompt("Skriv et brugernavn?", "iliakan");

return loadJson(`https://api.github.com/users/${name}`)
.then(user => {
alert(`Full name: ${user.name}.`);
alert(`Fulde navn: ${user.name}.`);
return user;
})
.catch(err => {
if (err instanceof HttpError && err.response.status == 404) {
alert("No such user, please reenter.");
alert("Brugeren findes ikke. Indtast et nyt brugernavn.");
return demoGithubUser();
} else {
throw err;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@

That's the case when knowing how it works inside is helpful.
Det er her hvor det er godt at vide hvordan det virker inde i motorrummet.

Du kan bare behandle `async` kald som et promise og tilføje `.then` til det:

Just treat `async` call as promise and attach `.then` to it:
```js run
async function wait() {
await new Promise(resolve => setTimeout(resolve, 1000));
Expand All @@ -10,7 +11,7 @@ async function wait() {
}

function f() {
// shows 10 after 1 second
// viser 10 efter 1 sekund
*!*
wait().then(result => alert(result));
*/!*
Expand Down
12 changes: 6 additions & 6 deletions 1-js/11-async/08-async-await/03-async-from-regular/task.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

# Call async from non-async
# Kald async fra ikke-async

We have a "regular" function called `f`. How can you call the `async` function `wait()` and use its result inside of `f`?
Vi har en "normal" function kaldet `f`. Hvordan kan du kalde den `async` function `wait()` og bruge dens resultat inde i `f`?

```js
async function wait() {
Expand All @@ -11,10 +11,10 @@ async function wait() {
}

function f() {
// ...what should you write here?
// we need to call async wait() and wait to get 10
// remember, we can't use "await"
// ... hvad skal vi skrive her?
// vi har brug for at kalde den asynkrone wait() og vente på at få 10
// husk, vi kan ikke bruge "await"
}
```

P.S. The task is technically very simple, but the question is quite common for developers new to async/await.
P.S. Opgaven er teknisk set meget simpel, men spørgsmålet er ganske almindeligt for udviklere, der er nye i async/await.
48 changes: 24 additions & 24 deletions 1-js/11-async/08-async-await/04-promise-all-failure/solution.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,52 @@

The root of the problem is that `Promise.all` immediately rejects when one of its promises rejects, but it do nothing to cancel the other promises.
Roden til problemet er, at `Promise.all` umiddelbart afviser, når en af dens promises afviser, men den gør intet for at annullere de andre promises.

In our case, the second query fails, so `Promise.all` rejects, and the `try...catch` block catches this error.Meanwhile, other promises are *not affected* - they independently continue their execution. In our case, the third query throws an error of its own after a bit of time. And that error is never caught, we can see it in the console.
I vores tilfælde fejler den anden forespørgsel, så `Promise.all` afviser, og `try...catch` blokken fanger denne fejl. Mens de andre promises ikke er påvirket - de fortsætter uafhængigt deres eksekvering. I vores tilfælde kaster den tredje forespørgsel en fejl selv efter et stykke tid. Og den fejl bliver aldrig fanget, vi kan se den i konsollen.

The problem is especially dangerous in server-side environments, such as Node.js, when an uncaught error may cause the process to crash.
Problemet er især farligt i server-side miljøer, såsom Node.js, hvor en ikke-fanget fejl kan forårsage, at processen går ned.

How to fix it?
Hvordan fikser vi det?

An ideal solution would be to cancel all unfinished queries when one of them fails. This way we avoid any potential errors.
En idéel løsning ville være at annullere alle uafsluttede forespørgsler, når en af dem fejler. På denne måde undgår vi eventuelle fejl.

However, the bad news is that service calls (such as `database.query`) are often implemented by a 3rd-party library which doesn't support cancellation. Then there's no way to cancel a call.
Men den dårlige nyheder er, at servicekald (såsom `database.query`) ofte er implementeret af en 3rd-parts bibliotek, som ikke understøtter annullering. Så der er ingen måde at annullere et kald.

As an alternative, we can write our own wrapper function around `Promise.all` which adds a custom `then/catch` handler to each promise to track them: results are gathered and, if an error occurs, all subsequent promises are ignored.
Som et alternativ kan vi skrive vores egen wrapper omkring `Promise.all` som tilføjer en custom `then/catch` handler til hver promise for at spore dem: resultaterne samles og, hvis en fejl opstår, ignoreres alle efterfølgende promises.

```js
function customPromiseAll(promises) {
return new Promise((resolve, reject) => {
const results = [];
let resultsCount = 0;
let hasError = false; // we'll set it to true upon first error
let hasError = false; // vi sætter den til true ved første fejl vi møder

promises.forEach((promise, index) => {
promise
.then(result => {
if (hasError) return; // ignore the promise if already errored
if (hasError) return; // ignorer promise hvis den allerede er fejlet
results[index] = result;
resultsCount++;
if (resultsCount === promises.length) {
resolve(results); // when all results are ready - successs
resolve(results); // når alle resultater er klar - succes
}
})
.catch(error => {
if (hasError) return; // ignore the promise if already errored
hasError = true; // wops, error!
reject(error); // fail with rejection
if (hasError) return; // ignorer promise hvis den allerede er fejlet
hasError = true; // ups, fejl!
reject(error); // fejl med reject
});
});
});
}
```

This approach has an issue of its own - it's often undesirable to `disconnect()` when queries are still in the process.
Denne tilgang har sine egne udfordringer - det er ofte uønsket at kalde `disconnect()` når der stadig er forespørgsler i processen.

It may be important that all queries complete, especially if some of them make important updates.
Det kan være vigtigt at alle forespørgsler gennemføres, især hvis nogle af dem indeholder vigtige opdateringer.

So we should wait until all promises are settled before going further with the execution and eventually disconnecting.
Så vi bør vente indtil alle promise er afsluttet, før vi går videre med eksekveringen og til sidst frakobler.

Here's another implementation. It behaves similar to `Promise.all` - also resolves with the first error, but waits until all promises are settled.
Her er en anden implementering. Den opfører sig i stil med `Promise.all` - den resolver også ved den første fejl, men venter indtil alle promise er afsluttet.

```js
function customPromiseAllWait(promises) {
Expand Down Expand Up @@ -80,16 +80,16 @@ function customPromiseAllWait(promises) {
}
```

Now `await customPromiseAllWait(...)` will stall the execution until all queries are processed.
Nu vil `await customPromiseAllWait(...)` tilbageholde udførelsen indtil alle forespørgsler er behandlet. Hvis der opstår en fejl, vil den blive fanget i `try...catch` blokken, og vi kan være sikre på, at alle forespørgsler er afsluttet, før vi går videre.

This is a more reliable approach, as it guarantees a predictable execution flow.
Dette er en mere pålidelig tilgang, da den garanterer et forudsigeligt eksekveringsflow.

Lastly, if we'd like to process all errors, we can use either use `Promise.allSettled` or write a wrapper around it to gathers all errors in a single [AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError) object and rejects with it.
Til sidst, hvis vi vil behandle alle fejl, kan vi bruge enten `Promise.allSettled` eller skrive en wrapper omkring for at samle alle fejl i et enkelt [AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError) objekt og afvise med det.

```js
// wait for all promises to settle
// return results if no errors
// throw AggregateError with all errors if any
// vent på at alle promise er afsluttet
// returner resultater hvis ingen fejl
// kast AggregateError med alle fejl hvis nogen
function allOrAggregateError(promises) {
return Promise.allSettled(promises).then(results => {
const errors = [];
Expand All @@ -104,7 +104,7 @@ function allOrAggregateError(promises) {
});

if (errors.length > 0) {
throw new AggregateError(errors, 'One or more promises failed');
throw new AggregateError(errors, 'En eller flere promises fejlede');
}

return values;
Expand Down
38 changes: 19 additions & 19 deletions 1-js/11-async/08-async-await/04-promise-all-failure/task.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@

# Dangerous Promise.all
# Farlig Promise.all

`Promise.all` is a great way to parallelize multiple operations. It's especially useful when we need to make parallel requests to multiple services.
`Promise.all` er en fantastisk måde at køre flere operationer parallelt. Det er især nyttigt når vi har brug for at lave flere forespørgsler til forskellige services samtidigt.

However, there's a hidden danger. We'll see an example in this task and explore how to avoid it.
Men, der er en skjult fare. Vi vil se et eksempel i denne opgave og udforske, hvordan man undgår den.

Let's say we have a connection to a remote service, such as a database.
Lad os sige, vi har en forbindelse til en ekstern service, såsom en database.

There're two functions: `connect()` and `disconnect()`.
Der er to funktioner: `connect()` og `disconnect()`.

When connected, we can send requests using `database.query(...)` - an async function which usually returns the result but also may throw an error.
Når den er forbundet, kan vi sende forespørgsler ved hjælp af `database.query(...)` - en async function, som normalt returnerer resultatet, men også kan kaste en fejl.

Here's a simple implementation:
Her er en simpel implementering af det:

```js
let database;
Expand All @@ -28,21 +28,21 @@ function disconnect() {
database = null;
}

// intended usage:
// beregnet brug:
// connect()
// ...
// database.query(true) to emulate a successful call
// database.query(false) to emulate a failed call
// database.query(true) for at emulere et succesfuldt kald
// database.query(false) for at emulere et mislykket kald
// ...
// disconnect()
```

Now here's the problem.
Se her er problemet.

We wrote the code to connect and send 3 queries in parallel (all of them take different time, e.g. 100, 200 and 300ms), then disconnect:
Vi skrev koden til at forbinde og sende 3 forespørgsler parallelt (alle tager forskellig tid, f.eks. 100, 200 og 300 ms), for derefter at frakoble igen:

```js
// Helper function to call async function `fn` after `ms` milliseconds
// Hjælperfunktion til at kalde async funktion `fn` efter `ms` millisekunder
function delay(fn, ms) {
return new Promise((resolve, reject) => {
setTimeout(() => fn().then(resolve, reject), ms);
Expand All @@ -54,16 +54,16 @@ async function run() {

try {
await Promise.all([
// these 3 parallel jobs take different time: 100, 200 and 300 ms
// we use the `delay` helper to achieve this effect
// disse 3 paralelle jobs tager forskellig tid: 100, 200 og 300 ms
// vi bruger `delay` hjælperen for at opnå denne effekt
*!*
delay(() => database.query(true), 100),
delay(() => database.query(false), 200),
delay(() => database.query(false), 300)
*/!*
]);
} catch(error) {
console.log('Error handled (or was it?)');
console.log('Fejl håndteret (eller er den?)');
}

disconnect();
Expand All @@ -72,8 +72,8 @@ async function run() {
run();
```

Two of these queries happen to be unsuccessful, but we're smart enough to wrap the `Promise.all` call into a `try..catch` block.
To af disse forespørgsler viser sig at fejle, men vi var smarte nok til at wrappe `Promise.all` kaldet i en `try..catch` block.

However, this doesn't help! This script actually leads to an uncaught error in console!
Men lige meget hvad, så hjælper det ikke! Dette script fører faktisk til en ikke-fanget fejl i konsollen!

Why? How to avoid it?
Hvorfor? Hvordan undgår man det?
Loading