From c07df985f1466751eff45c881c3ac5460dcbdb22 Mon Sep 17 00:00:00 2001 From: Travis Briggs Date: Mon, 22 Jul 2024 18:57:50 -0700 Subject: [PATCH 01/21] Update article.md Remove non-inclusive language. --- 1-js/01-getting-started/1-intro/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/01-getting-started/1-intro/article.md b/1-js/01-getting-started/1-intro/article.md index 2f4f518f..a58d5d72 100644 --- a/1-js/01-getting-started/1-intro/article.md +++ b/1-js/01-getting-started/1-intro/article.md @@ -73,7 +73,7 @@ Examples of such restrictions include: This is called the "Same Origin Policy". To work around that, *both pages* must agree for data exchange and must contain special JavaScript code that handles it. We'll cover that in the tutorial. This limitation is, again, for the user's safety. A page from `http://anysite.com` which a user has opened must not be able to access another browser tab with the URL `http://gmail.com`, for example, and steal information from there. -- JavaScript can easily communicate over the net to the server where the current page came from. But its ability to receive data from other sites/domains is crippled. Though possible, it requires explicit agreement (expressed in HTTP headers) from the remote side. Once again, that's a safety limitation. +- JavaScript can easily communicate over the net to the server where the current page came from. But its ability to receive data from other sites/domains is severely limited. Though possible, it requires explicit agreement (expressed in HTTP headers) from the remote side. Once again, that's a safety limitation. ![](limitations.svg) From 5f40ec4eff039a06a9886161b1bf5b0b45260e2f Mon Sep 17 00:00:00 2001 From: ockley Date: Fri, 6 Mar 2026 13:13:33 +0100 Subject: [PATCH 02/21] Oversat til dansk --- .../2-dictionary-tostring/solution.md | 20 +-- .../2-dictionary-tostring/task.md | 20 +-- .../3-compare-calls/solution.md | 8 +- .../3-compare-calls/task.md | 8 +- .../04-prototype-methods/article.md | 160 +++++++++--------- 5 files changed, 108 insertions(+), 108 deletions(-) diff --git a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md index f3c9cf0e..234388df 100644 --- a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md +++ b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md @@ -1,31 +1,31 @@ -The method can take all enumerable keys using `Object.keys` and output their list. +Metoden kan tage alle enumerable (tælbare) nøgler ved hjælp af `Object.keys` og outputte deres liste. -To make `toString` non-enumerable, let's define it using a property descriptor. The syntax of `Object.create` allows us to provide an object with property descriptors as the second argument. +For at gøre `toString` non-enumerable, lad os definere den ved hjælp af en egenskabsbeskrivelse. Syntaksen for `Object.create` giver os mulighed for at give et objekt med egenskabsbeskrivelser som anden argument. ```js run *!* let dictionary = Object.create(null, { - toString: { // define toString property - value() { // the value is a function + toString: { // definer egenskaben toString + value() { // value er en funktion return Object.keys(this).join(); } } }); */!* -dictionary.apple = "Apple"; +dictionary.apple = "Æble"; dictionary.__proto__ = "test"; -// apple and __proto__ is in the loop +// Kun apple og __proto__ er i loopet for(let key in dictionary) { - alert(key); // "apple", then "__proto__" + alert(key); // "apple" og "__proto__" } -// comma-separated list of properties by toString +// kommasepareret liste af egenskaber fra toString alert(dictionary); // "apple,__proto__" ``` -When we create a property using a descriptor, its flags are `false` by default. So in the code above, `dictionary.toString` is non-enumerable. +Når vi opretter en egenskab ved hjælp af en egenskabsbeskrivelser, er dens flag som standard sat til `false`. Så i koden ovenfor er `dictionary.toString` non-enumerable. -See the chapter [](info:property-descriptors) for review. +Se kapitlet [](info:property-descriptors) for en gennemgang. diff --git a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md index 0d831f2c..82521674 100644 --- a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md +++ b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md @@ -2,30 +2,30 @@ importance: 5 --- -# Add toString to the dictionary +# Tilføj toString til ordbogen -There's an object `dictionary`, created as `Object.create(null)`, to store any `key/value` pairs. +Der er et objekt `dictionary`, oprettet som `Object.create(null)`, til at gemme enhver `key/value` par. -Add method `dictionary.toString()` into it, that should return a comma-delimited list of keys. Your `toString` should not show up in `for..in` over the object. +Tilføj metoden `dictionary.toString()` til det, som skal returnere en komma-separeret liste af nøgler. Din `toString` bør ikke vises i `for..in` over objektet. -Here's how it should work: +Den bør virke sådan her: ```js let dictionary = Object.create(null); *!* -// your code to add dictionary.toString method +// din kode til at tilføje dictionary.toString metoden */!* -// add some data -dictionary.apple = "Apple"; +// tilføj nogle data +dictionary.apple = "æble"; dictionary.__proto__ = "test"; // __proto__ is a regular property key here -// only apple and __proto__ are in the loop +// Kun apple og __proto__ er i loopet for(let key in dictionary) { - alert(key); // "apple", then "__proto__" + alert(key); // "apple" og "__proto__" } -// your toString in action +// din toString i aktion alert(dictionary); // "apple,__proto__" ``` diff --git a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/solution.md b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/solution.md index 90d3118b..995c79f2 100644 --- a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/solution.md +++ b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/solution.md @@ -1,7 +1,7 @@ -The first call has `this == rabbit`, the other ones have `this` equal to `Rabbit.prototype`, because it's actually the object before the dot. +Det første kald har `this == rabbit`, de andre har `this` lig med `Rabbit.prototype`, fordi det faktisk er objektet før punktummet. -So only the first call shows `Rabbit`, other ones show `undefined`: +Så kun det første kald viser `Rabbit`, andre viser `undefined`: ```js run function Rabbit(name) { @@ -11,9 +11,9 @@ Rabbit.prototype.sayHi = function() { alert( this.name ); } -let rabbit = new Rabbit("Rabbit"); +let rabbit = new Rabbit("Kanin"); -rabbit.sayHi(); // Rabbit +rabbit.sayHi(); // Kanin Rabbit.prototype.sayHi(); // undefined Object.getPrototypeOf(rabbit).sayHi(); // undefined rabbit.__proto__.sayHi(); // undefined diff --git a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md index 09bb7f1e..672883d4 100644 --- a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md +++ b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# The difference between calls +# Forskellen mellem kald -Let's create a new `rabbit` object: +Lad os oprette et nyt `rabbit` objekt: ```js function Rabbit(name) { @@ -14,10 +14,10 @@ Rabbit.prototype.sayHi = function() { alert(this.name); }; -let rabbit = new Rabbit("Rabbit"); +let rabbit = new Rabbit("Kanin"); ``` -These calls do the same thing or not? +Gør disse kald det samme eller gør de ikke? ```js rabbit.sayHi(); diff --git a/1-js/08-prototypes/04-prototype-methods/article.md b/1-js/08-prototypes/04-prototype-methods/article.md index 9c5f1eb3..3b54e6a9 100644 --- a/1-js/08-prototypes/04-prototype-methods/article.md +++ b/1-js/08-prototypes/04-prototype-methods/article.md @@ -1,31 +1,31 @@ -# Prototype methods, objects without __proto__ +# Prototype metoder, objekter uden __proto__ -In the first chapter of this section, we mentioned that there are modern methods to setup a prototype. +I det første kapitel i denne sektion nævnte vi, at der er moderne metoder til at sætte en prototype. -Setting or reading the prototype with `obj.__proto__` is considered outdated and somewhat deprecated (moved to the so-called "Annex B" of the JavaScript standard, meant for browsers only). +At sætte eller læse en prototype med `obj.__proto__` er betragtet som forældet og noget deprecated (flyttet til såkaldte "Annex B" i JavaScript-standarden, kun tilgængelig i browser-motorer). -The modern methods to get/set a prototype are: +De moderne metoder til at få/sætte en prototype er: -- [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returns the `[[Prototype]]` of `obj`. -- [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto`. +- [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returnerer `[[Prototype]]` af `obj`. +- [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sætter `[[Prototype]]` af `obj` til `proto`. -The only usage of `__proto__`, that's not frowned upon, is as a property when creating a new object: `{ __proto__: ... }`. +Den eneste brug af `__proto__`, der ikke rynkes på panden af er, som en en egenskab når der oprettes et nyt objekt: `{ __proto__: ... }`. -Although, there's a special method for this too: +Selvom der egentlig er en speciel metode for dette også: -- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` and optional property descriptors. +- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- opretter et tomt objekt med given `proto` som `[[Prototype]]` og valgfrie beskrivelser af egenskaber. -For instance: +For eksempel for at oprette et objekt med `animal` som prototype, kan vi bruge: ```js run let animal = { eats: true }; -// create a new object with animal as a prototype +// opret et nyt objekt med animal som prototype *!* -let rabbit = Object.create(animal); // same as {__proto__: animal} +let rabbit = Object.create(animal); // samme som {__proto__: animal} */!* alert(rabbit.eats); // true @@ -35,13 +35,13 @@ alert(Object.getPrototypeOf(rabbit) === animal); // true */!* *!* -Object.setPrototypeOf(rabbit, {}); // change the prototype of rabbit to {} +Object.setPrototypeOf(rabbit, {}); // Ændring af rabbits prototype til {} */!* ``` -The `Object.create` method is a bit more powerful, as it has an optional second argument: property descriptors. +Metoden `Object.create` er lidt mere kraftfuld, da den giver mulighed for at tilføje egenskaber til det nye objekt. Det er en valgfri anden parameter: egenskabsbeskrivelser. -We can provide additional properties to the new object there, like this: +Vi kan tilføje yderligere egenskaber til det nye objekt der, som dette: ```js run let animal = { @@ -57,9 +57,9 @@ let rabbit = Object.create(animal, { alert(rabbit.jumps); // true ``` -The descriptors are in the same format as described in the chapter . +Muligheden for beskrivelser er det samme format som beskrevet i kapitlet . -We can use `Object.create` to perform an object cloning more powerful than copying properties in `for..in`: +Vi kan bruge `Object.create` til at udføre en kloning af et objekt der er mere effektiv end at kopiere de enkelte egenskaber i et `for..in` loop: ```js let clone = Object.create( @@ -67,125 +67,125 @@ let clone = Object.create( ); ``` -This call makes a truly exact copy of `obj`, including all properties: enumerable and non-enumerable, data properties and setters/getters -- everything, and with the right `[[Prototype]]`. +Dette kald laver en helt præcis kopi af `obj`, inklusiv alle egenskaber: både enumerable og ikke-enumerable, data egenskaber og setters/getters -- alt, og med den rigtige `[[Prototype]]`. -## Brief history +## Et lille blik på historien bag -There're so many ways to manage `[[Prototype]]`. How did that happen? Why? +Der er SÅ mange måder at håndtere `[[Prototype]]`. Hvordan kunne det dog komme dertil? -That's for historical reasons. +Det er ganske enkelt en række historiske årsdager. -The prototypal inheritance was in the language since its dawn, but the ways to manage it evolved over time. +Nedarvning ved prototype har været muligt siden sprogets start, men måderne at håndtere den har udviklet sig over tid. -- The `prototype` property of a constructor function has worked since very ancient times. It's the oldest way to create objects with a given prototype. -- Later, in the year 2012, `Object.create` appeared in the standard. It gave the ability to create objects with a given prototype, but did not provide the ability to get/set it. Some browsers implemented the non-standard `__proto__` accessor that allowed the user to get/set a prototype at any time, to give more flexibility to developers. -- Later, in the year 2015, `Object.setPrototypeOf` and `Object.getPrototypeOf` were added to the standard, to perform the same functionality as `__proto__`. As `__proto__` was de-facto implemented everywhere, it was kind-of deprecated and made its way to the Annex B of the standard, that is: optional for non-browser environments. -- Later, in the year 2022, it was officially allowed to use `__proto__` in object literals `{...}` (moved out of Annex B), but not as a getter/setter `obj.__proto__` (still in Annex B). +- Egenskaben `prototype` som led i en konstruktørfunktion har virket helt fra begyndelsen. Det er den ældste måde at oprette objekter med en given prototype. +- Senere, i 2012, blev `Object.create` vedtaget som standard. Den gav mulighed for at oprette objekter med en given prototype, men gav ikke mulighed for at bruge get/set på den. Nogle browsere implementerede den ikke-standard `__proto__` tilgang, som tillod brugeren at bruge get/set på en prototype uden for konstruktøren, for at give mere fleksibilitet til udviklere. +- Senere, i 2015, blev `Object.setPrototypeOf` og `Object.getPrototypeOf` tilføjet til standarden, for at udføre samme funktionalitet som `__proto__`. Da `__proto__` var de-facto implementeret overalt, blev det delvis deprecated og bragt til Annex B af standarden, altså valgfrit for ikke-browser miljøer. +- Senere, i 2022, blev det officielt tilladt at bruge `__proto__` i objekt-literaler `{...}` (flyttet ud af Annex B), men ikke som en getter/setter `obj.__proto__` (stadig i Annex B). -Why was `__proto__` replaced by the functions `getPrototypeOf/setPrototypeOf`? +Hvorfor var `__proto__` erstattet af funktionerne `getPrototypeOf/setPrototypeOf`? -Why was `__proto__` partially rehabilitated and its usage allowed in `{...}`, but not as a getter/setter? +Hvorfor var `__proto__` delvist genindført så det er tilladt i objekt-literaler `{...}`, men ikke som en getter/setter `obj.__proto__`? -That's an interesting question, requiring us to understand why `__proto__` is bad. +Det er et interessant spørgsmål, der kræver, at vi forstår hvorfor `__proto__` er dårlig. -And soon we'll get the answer. +Og snart vil vi få svaret. -```warn header="Don't change `[[Prototype]]` on existing objects if speed matters" -Technically, we can get/set `[[Prototype]]` at any time. But usually we only set it once at the object creation time and don't modify it anymore: `rabbit` inherits from `animal`, and that is not going to change. +```warn header="Lad være med at ændre `[[Prototype]]` på eksisterende objekter hvis hastighed er vigtig" +Teknisk set kan vi oprette can get/set på en `[[Prototype]]` når som helst. Men i praksis sker det næsten altid kun ved oprettelsen af objektet. Ofte sætter vi kun `[[Prototype]]` én gang ved oprettelsen af objektet og undlader efterfølgende at ændre den ikke igen: `rabbit` nedarver fra `animal`, og det ændres ikke. -And JavaScript engines are highly optimized for this. Changing a prototype "on-the-fly" with `Object.setPrototypeOf` or `obj.__proto__=` is a very slow operation as it breaks internal optimizations for object property access operations. So avoid it unless you know what you're doing, or JavaScript speed totally doesn't matter for you. +JavaScript-motorer er højst optimerede til dette. Ændring af en prototype "on-the-fly" med `Object.setPrototypeOf` eller `obj.__proto__=` er en meget langsom operation, da den bryder interne optimeringer for objektegenskabstilgange. Undgå derfor at ændre prototypen, medmindre du ved hvad du gør, eller JavaScript-hastighed ikke spiller en rolle for dig. ``` -## "Very plain" objects [#very-plain] +## "Meget simple" objekter [#very-plain] -As we know, objects can be used as associative arrays to store key/value pairs. +Som vi ved kan objekter bruges som associative arrays til at gemme nøgle/værdi-par. -...But if we try to store *user-provided* keys in it (for instance, a user-entered dictionary), we can see an interesting glitch: all keys work fine except `"__proto__"`. +...Men hvis vi forsøger at gemme *brugerdefinerede* nøgler i det (for eksempel en brugerdefineret ordbog), kan vi se et interessant glitch: alle nøgler virker fint, bortset fra `"__proto__"`. -Check out the example: +Så for eksempel nedenfor: ```js run let obj = {}; -let key = prompt("What's the key?", "__proto__"); -obj[key] = "some value"; +let key = prompt("Hvad er nøglen?", "__proto__"); +obj[key] = "en værdi"; -alert(obj[key]); // [object Object], not "some value"! +alert(obj[key]); // [object Object], ikke "en værdi"! ``` -Here, if the user types in `__proto__`, the assignment in line 4 is ignored! +Her vil linje 4 ignoreres, hvis brugeren skriver `__proto__` i prompten! -That could surely be surprising for a non-developer, but pretty understandable for us. The `__proto__` property is special: it must be either an object or `null`. A string can not become a prototype. That's why assigning a string to `__proto__` is ignored. +Det er umiddelbart overraskende, men egentlig meget logisk, når vi husker på at egenskaben `__proto__` er lidt speciel: Den skal enten være et objekt eller `null`. En streng kan ikke blive en prototype. Derfor ignoreres tildeling af en streng til `__proto__`. -But we didn't *intend* to implement such behavior, right? We want to store key/value pairs, and the key named `"__proto__"` was not properly saved. So that's a bug! +Det var var jo ikke vores *plan* at den skulle opføre sig på den måde, vel? Vi vil gerne gemme nøgle/værdi-par, og nøglen kaldt `"__proto__"` blev ikke korrekt gemt. Så det er en fejl! -Here the consequences are not terrible. But in other cases we may be storing objects instead of strings in `obj`, and then the prototype will indeed be changed. As a result, the execution will go wrong in totally unexpected ways. +Her er konsekvenserne ikke så farlige. Men i andre tilfælde kan vi gemme objekter i stedet for strenge i `obj`, og så vil prototypen faktisk blive ændret. Som resultat vil eksekveringen gå galt på helt uventede måder. -What's worse -- usually developers do not think about such possibility at all. That makes such bugs hard to notice and even turn them into vulnerabilities, especially when JavaScript is used on server-side. +Det værre -- ofte tænker udviklere ikke over denne mulighed overhovedet. Det gør sådanne fejl svære at opdage og endda omvandles til sikkerhedsproblemer, især når JavaScript bruges på server-side. -Unexpected things also may happen when assigning to `obj.toString`, as it's a built-in object method. +Uventede ting kan også ske når vi tildeler til `obj.toString`, da det er en indbygget objektmetode. -How can we avoid this problem? +Hvordan kan vi undgå dette problem? -First, we can just switch to using `Map` for storage instead of plain objects, then everything's fine: +Først og fremmest kan vi skifte til at bruge `Map` for lagring i stedet for almindelige objekter, så alt er i orden: ```js run let map = new Map(); -let key = prompt("What's the key?", "__proto__"); -map.set(key, "some value"); +let key = prompt("Hvad er nøglen?", "__proto__"); +map.set(key, "en værdi"); -alert(map.get(key)); // "some value" (as intended) +alert(map.get(key)); // "en værdi" (som det var meningen) ``` -...But `Object` syntax is often more appealing, as it's more concise. +...Men `Object` syntaksen appelerer mere til de fleste - og den er kortere. -Fortunately, we *can* use objects, because language creators gave thought to that problem long ago. +Heldigvis *kan* vi bruge objekter fordi udviklerne af sproget har tænkt over dette problem for længe siden. -As we know, `__proto__` is not a property of an object, but an accessor property of `Object.prototype`: +Som vi ved er `__proto__` ikke i sig selv en egenskab af et objekt, men en accessor-egenskab af `Object.prototype`: ![](object-prototype-2.svg) -So, if `obj.__proto__` is read or set, the corresponding getter/setter is called from its prototype, and it gets/sets `[[Prototype]]`. +Så, hvis `obj.__proto__` læses eller sættes vil dens respektive getter/setter kaldes fra dens prototype, som så får eller sætter værdien af `[[Prototype]]`. -As it was said in the beginning of this tutorial section: `__proto__` is a way to access `[[Prototype]]`, it is not `[[Prototype]]` itself. +Som det blev sagt i begyndelsen: `__proto__` er en måde at tilgå `[[Prototype]]`, det er ikke selve objektet `[[Prototype]]`. -Now, if we intend to use an object as an associative array and be free of such problems, we can do it with a little trick: +Så, hvis vi planlægger at bruge et objekt som et associativt array og være fri for sådanne problemer, kan vi gøre det med et lille trick: ```js run *!* let obj = Object.create(null); -// or: obj = { __proto__: null } +// eller: obj = { __proto__: null } */!* -let key = prompt("What's the key?", "__proto__"); -obj[key] = "some value"; +let key = prompt("Hvad er nøglen?", "__proto__"); +obj[key] = "en værdi"; -alert(obj[key]); // "some value" +alert(obj[key]); // "en værdi" ``` -`Object.create(null)` creates an empty object without a prototype (`[[Prototype]]` is `null`): +`Object.create(null)` opretter et tomt objekt uden en prototype (`[[Prototype]]` er `null`): ![](object-prototype-null.svg) -So, there is no inherited getter/setter for `__proto__`. Now it is processed as a regular data property, so the example above works right. +På denne måde er der ingen arvede getter/setter for `__proto__`. Nu bliver det behandlet som en almindelig dataegenskab, så eksemplet ovenfor fungerer korrekt. -We can call such objects "very plain" or "pure dictionary" objects, because they are even simpler than the regular plain object `{...}`. +Vi kan kalde sådanne objekter "helt rene", fordi de er endnu mere simple end regulære rene objekter `{...}`. -A downside is that such objects lack any built-in object methods, e.g. `toString`: +En ulempe er, at sådanne objekter mangler alle indbyggede objektmetoder, f.eks. `toString`: ```js run *!* let obj = Object.create(null); */!* -alert(obj); // Error (no toString) +alert(obj); // Fejl (ingen toString) ``` -...But that's usually fine for associative arrays. +...men det er normalt ikke et problem for associative arrays. -Note that most object-related methods are `Object.something(...)`, like `Object.keys(obj)` -- they are not in the prototype, so they will keep working on such objects: +Bemærk, at de fleste objektrelaterede metoder er `Object.something(...)`, som `Object.keys(obj)` -- de er ikke i prototype, så de vil fortsat fungere på denne slags objekter: ```js run @@ -196,28 +196,28 @@ chineseDictionary.bye = "再见"; alert(Object.keys(chineseDictionary)); // hello,bye ``` -## Summary +## Opsummering -- To create an object with the given prototype, use: +- For at oprette et objekt med den givne prototype, brug: - - literal syntax: `{ __proto__: ... }`, allows to specify multiple properties - - or [Object.create(proto[, descriptors])](mdn:js/Object/create), allows to specify property descriptors. + - literal syntax: `{ __proto__: ... }`, tillader at specificere flere egenskaber + - eller [Object.create(proto[, descriptors])](mdn:js/Object/create), tillader at specificere egenskabsbeskrivelser. - The `Object.create` provides an easy way to shallow-copy an object with all descriptors: + `Object.create` giver en let måde at lave en flad kopi af et objekt med alle beskrivelser: ```js let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)); ``` -- Modern methods to get/set the prototype are: +- Moderne metoder til at få eller sætte en prototype er: - - [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returns the `[[Prototype]]` of `obj` (same as `__proto__` getter). - - [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto` (same as `__proto__` setter). + - [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returnerer `[[Prototype]]` of `obj` (samme som `__proto__` getter). + - [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sætter `[[Prototype]]` of `obj` til `proto` (samme som `__proto__` setter). -- Getting/setting the prototype using the built-in `__proto__` getter/setter isn't recommended, it's now in the Annex B of the specification. +- At få eller sætte en prototype ved hjælp af de indbyggede `__proto__` getter/setter anbefales ikke, da det nu er i Annex B af specifikationen. -- We also covered prototype-less objects, created with `Object.create(null)` or `{__proto__: null}`. +- Vi dækkede også objekter uden prototype, oprettet med `Object.create(null)` eller `{__proto__: null}`. - These objects are used as dictionaries, to store any (possibly user-generated) keys. + Disse objekter bruges som "dictionary" (ordbøger) til at gemme enhver (muligvis bruger-genereret) nøgle. - Normally, objects inherit built-in methods and `__proto__` getter/setter from `Object.prototype`, making corresponding keys "occupied" and potentially causing side effects. With `null` prototype, objects are truly empty. + Normalt arver objekter indbyggede metoder og `__proto__` getter/setter fra `Object.prototype`, hvilket gør de tilsvarende nøgler "optaget" og potentielt forårsager sideeffekter. Med `null` prototype er objekterne virkelig tomme. From d7531fecfbc385f56980738b2229392d8ae8fe1c Mon Sep 17 00:00:00 2001 From: ockley Date: Fri, 6 Mar 2026 14:04:05 +0100 Subject: [PATCH 03/21] oversat til dansk --- .../01-class/1-rewrite-to-class/task.md | 6 +- 1-js/09-classes/01-class/article.md | 236 +++++++++--------- 1-js/09-classes/index.md | 2 +- 3 files changed, 122 insertions(+), 122 deletions(-) diff --git a/1-js/09-classes/01-class/1-rewrite-to-class/task.md b/1-js/09-classes/01-class/1-rewrite-to-class/task.md index 4477de67..5c701276 100644 --- a/1-js/09-classes/01-class/1-rewrite-to-class/task.md +++ b/1-js/09-classes/01-class/1-rewrite-to-class/task.md @@ -2,8 +2,8 @@ importance: 5 --- -# Rewrite to class +# Omskriv til en klasse -The `Clock` class (see the sandbox) is written in functional style. Rewrite it in the "class" syntax. +Klassen `Clock` (se i sandkassen) er skrevet med funktioner. Omskriv den til "class" syntaks. -P.S. The clock ticks in the console, open it to see. +P.S. Klokken tikker i konsollen, åbn den for at se. diff --git a/1-js/09-classes/01-class/article.md b/1-js/09-classes/01-class/article.md index 135d2492..c0501fe7 100644 --- a/1-js/09-classes/01-class/article.md +++ b/1-js/09-classes/01-class/article.md @@ -1,19 +1,19 @@ -# Class basic syntax +# Klasser: Grundlæggende syntaks ```quote author="Wikipedia" -In object-oriented programming, a *class* is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods). +I objekt-orienteret programmering, er en *klasse* (class) en udvidelig program-kodetemplate til at skabe objekter, der giver initiale værdier for tilstand (medlemsvariable) og implementeringer af adfærd (medlemsfunktioner eller metoder). ``` -In practice, we often need to create many objects of the same kind, like users, or goods or whatever. +I praksis har vi ofte brug for at skabe mange objekter af samme type, som f.eks. brugere eller varer eller hvad som helst. -As we already know from the chapter , `new function` can help with that. +Som vi allerede ved fra kapitlet , kan `new function` hjælpe med det. -But in the modern JavaScript, there's a more advanced "class" construct, that introduces great new features which are useful for object-oriented programming. +Men i moderne JavaScript, er der en mere avanceret "class" konstruktion, der introducerer store nye funktioner, som er nyttige for objekt-orienteret programmering. -## The "class" syntax +## Syntaks for "class" -The basic syntax is: +Den grundlæggende syntaks er: ```js class MyClass { // class methods @@ -25,11 +25,11 @@ class MyClass { } ``` -Then use `new MyClass()` to create a new object with all the listed methods. +Derefter bruges `new MyClass()` til at oprette et nyt objekt med alle de opførte metoder. -The `constructor()` method is called automatically by `new`, so we can initialize the object there. +Metoden `constructor()` kaldes automatisk af `new`, så vi kan initialisere objektet der. -For example: +For eksempel: ```js run class User { @@ -45,32 +45,32 @@ class User { } // Usage: -let user = new User("John"); +let user = new User("Karsten"); user.sayHi(); ``` -When `new User("John")` is called: -1. A new object is created. -2. The `constructor` runs with the given argument and assigns it to `this.name`. +Når `new User("Karsten")` kaldes, sker der følgende: +1. Et nyt objekt oprettes. +2. Metoden `constructor` kører med det givne argument og tildeler det til `this.name`. -...Then we can call object methods, such as `user.sayHi()`. +...efter det kan vi kalde objektets metoder, såsom `user.sayHi()`. -```warn header="No comma between class methods" -A common pitfall for novice developers is to put a comma between class methods, which would result in a syntax error. +```warn header="Ingen komma mellem class metoder" +En kendt fejl i begyndelsen er at putte kommaer mellem class metoder - det vil føre tilen syntaksfejl. -The notation here is not to be confused with object literals. Within the class, no commas are required. +Den notation her er ikke at forveksle med object literals. Inden for class, er kommaer ikke nødvendige. ``` -## What is a class? +## Hvad er en class? -So, what exactly is a `class`? That's not an entirely new language-level entity, as one might think. +Så, hvad er `class` egentlig for en størrelse? Det er faktisk ikke så nyt et koncept på sprogniveau, som man måske skulle forestille sig. -Let's unveil any magic and see what a class really is. That'll help in understanding many complex aspects. +Lad os prøve at pakke det ud lidt ad gangen. Det vil hjælpe med at forstå de mere komplekse aspekter. -In JavaScript, a class is a kind of function. +I JavaScript er en klasse en slags funktion. -Here, take a look: +Lad os se på følgende: ```js run class User { @@ -78,24 +78,24 @@ class User { sayHi() { alert(this.name); } } -// proof: User is a function +// Bevis: User er en function *!* alert(typeof User); // function */!* ``` -What `class User {...}` construct really does is: +Det konstruktionen `class User {...}` i virkeligheden gør er: -1. Creates a function named `User`, that becomes the result of the class declaration. The function code is taken from the `constructor` method (assumed empty if we don't write such method). -2. Stores class methods, such as `sayHi`, in `User.prototype`. +1. Opretter en funktion kaldet `User`, som bliver resultatet af class-deklarationen. Funktionens kode bliver taget fra `constructor`-metoden (antaget tom, hvis vi ikke skriver en sådan). +2. Gemmer class-metoder, såsom `sayHi`, i `User.prototype`. -After `new User` object is created, when we call its method, it's taken from the prototype, just as described in the chapter . So the object has access to class methods. +Efter at et `new User`-objekt er oprettet, når vi kalder dens metode, bliver den taget fra prototype, ligesom beskrevet i kapitlet . Så har objektet adgang til class-metoder. -We can illustrate the result of `class User` declaration as: +Vi kan illustrere resultatet af `class User`-deklarationen som: ![](class-user.svg) -Here's the code to introspect it: +Her er koden til at kigge nærmere på det: ```js run class User { @@ -103,50 +103,50 @@ class User { sayHi() { alert(this.name); } } -// class is a function +// class er en function alert(typeof User); // function -// ...or, more precisely, the constructor method +// ...eller, mere præcist, konstruktøren alert(User === User.prototype.constructor); // true -// The methods are in User.prototype, e.g: -alert(User.prototype.sayHi); // the code of the sayHi method +// Metoderne findes i User.prototype, f. eks. sayHi: +alert(User.prototype.sayHi); // her er koden for metoden sayHi -// there are exactly two methods in the prototype +// der er præcis to metoder i prototypen alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi ``` -## Not just a syntactic sugar +## Det er ikke kun en syntactic sugar -Sometimes people say that `class` is a "syntactic sugar" (syntax that is designed to make things easier to read, but doesn't introduce anything new), because we could actually declare the same thing without using the `class` keyword at all: +Du vil høre folk sige at `class` er en "syntactic sugar" (syntaks der er designet til at gøre ting lettere at læse, men ikke introducerer noget nyt), fordi vi faktisk kunne erklære det samme uden at bruge `class`-nøgleordet: ```js run -// rewriting class User in pure functions +// omskrivning af class User til kun at bruge funktioner -// 1. Create constructor function +// 1. Opret constructor function User(name) { this.name = name; } -// a function prototype has "constructor" property by default, -// so we don't need to create it +// En function prototype har egenskaben "constructor" som standard, +// så vi behøver ikke at oprette den -// 2. Add the method to prototype +// 2. Tilføj metoden til prototype User.prototype.sayHi = function() { alert(this.name); }; -// Usage: -let user = new User("John"); +// Brug: +let user = new User("Karsten"); user.sayHi(); ``` -The result of this definition is about the same. So, there are indeed reasons why `class` can be considered a syntactic sugar to define a constructor together with its prototype methods. +Resultatet af denne definition er omkring det samme. Så, der er faktisk grunde til at `class` kan betragtes som en syntactic sugar til at definere en constructor sammen med dens prototype metoder. -Still, there are important differences. +Alligevel, der er vigtige forskelle. -1. First, a function created by `class` is labelled by a special internal property `[[IsClassConstructor]]: true`. So it's not entirely the same as creating it manually. +1. Først, en funktion oprettet af `class` er mærket med en speciel intern egenskab `[[IsClassConstructor]]: true`. Så det er ikke helt det samme som at oprette den manuelt. - The language checks for that property in a variety of places. For example, unlike a regular function, it must be called with `new`: + SProget tjekker for denne egenskab i en række sammenhænge. For eksempel, i modsætning til en almindelig funktion, skal den kaldes med `new`: ```js run class User { @@ -157,7 +157,7 @@ Still, there are important differences. User(); // Error: Class constructor User cannot be invoked without 'new' ``` - Also, a string representation of a class constructor in most JavaScript engines starts with the "class..." + Derudover vil en repræsentation af klassen som en streng i de fleste JavaScript-motorer starte med "class..." ```js run class User { @@ -166,23 +166,23 @@ Still, there are important differences. alert(User); // class User { ... } ``` - There are other differences, we'll see them soon. + Der er også andre forskelle som vi snart vil se. -2. Class methods are non-enumerable. - A class definition sets `enumerable` flag to `false` for all methods in the `"prototype"`. +2. Class metoder er ikke-enumerable. + En class definition sætter flaget `enumerable` til `false` for alle metoder i dens `"prototype"`. - That's good, because if we `for..in` over an object, we usually don't want its class methods. + Det er godt, fordi hvis vi bruger `for..in` på et objekt, vil vi normalt ikke vil have dets class metoder. -3. Classes always `use strict`. - All code inside the class construct is automatically in strict mode. +3. Class bruger altid `use strict`. + Al kode inde i en class konstruktion er automatisk sat til strict mode. -Besides, `class` syntax brings many other features that we'll explore later. +Der er også andre features ved `class` syntaksen som vi kigger på senere. ## Class Expression -Just like functions, classes can be defined inside another expression, passed around, returned, assigned, etc. +På samme måde som funktioner, kan classes defineres indeni en andet udtryk (expression), videregives, returneres, tildeles osv. -Here's an example of a class expression: +Her er et eksempel på en class expression: ```js let User = class { @@ -192,29 +192,29 @@ let User = class { }; ``` -Similar to Named Function Expressions, class expressions may have a name. +På samme måde som "Named Function Expressions", kan class udtryk også have et navn. -If a class expression has a name, it's visible inside the class only: +Hvis et class udtryk har et navn, er det kun synligt inden for klassen selv: ```js run // "Named Class Expression" -// (no such term in the spec, but that's similar to Named Function Expression) +// (der er ikke sådan et navn i specifikationen, men det er det samme som med Named Function Expression) let User = class *!*MyClass*/!* { sayHi() { - alert(MyClass); // MyClass name is visible only inside the class + alert(MyClass); // Navnet MyClass er kun synligt inden for klassen selv } }; -new User().sayHi(); // works, shows MyClass definition +new User().sayHi(); // virker, viser MyClass definition -alert(MyClass); // error, MyClass name isn't visible outside of the class +alert(MyClass); // fejl, navnet MyClass er ikke synligt uden for klassen ``` -We can even make classes dynamically "on-demand", like this: +Vi kan endda oprette klasser dynamisk "on-demand", som dette: ```js run function makeClass(phrase) { - // declare a class and return it + // deklarerer en klasse og returner den return class { sayHi() { alert(phrase); @@ -222,24 +222,24 @@ function makeClass(phrase) { }; } -// Create a new class -let User = makeClass("Hello"); +// Opret en ny klasse +let User = makeClass("Hej!"); -new User().sayHi(); // Hello +new User().sayHi(); // Hej! ``` ## Getters/setters -Just like literal objects, classes may include getters/setters, computed properties etc. +På samme måde som med objekter kan klasser have getters og setters, computed properties osv. -Here's an example for `user.name` implemented using `get/set`: +Her er et eksempel for `user.name` implementeret ved hjælp af `get/set`: ```js run class User { constructor(name) { - // invokes the setter + // aktiverer dens setter this.name = name; } @@ -253,7 +253,7 @@ class User { set name(value) { */!* if (value.length < 4) { - alert("Name is too short."); + alert("Navnet er for kort."); return; } this._name = value; @@ -261,17 +261,17 @@ class User { } -let user = new User("John"); -alert(user.name); // John +let user = new User("Karsten"); +alert(user.name); // Karsten -user = new User(""); // Name is too short. +user = new User("Bo"); // Navnet er for kort. ``` -Technically, such class declaration works by creating getters and setters in `User.prototype`. +Teknisk set virker sådanne deklarationer ved at oprette getter og setter i `User.prototype`. ## Computed names [...] -Here's an example with a computed method name using brackets `[...]`: +Her er et eksempel hvor navnet på metoden er udregnet ved hjælp af brackets `[...]`: ```js run class User { @@ -279,7 +279,7 @@ class User { *!* ['say' + 'Hi']() { */!* - alert("Hello"); + alert("Hej"); } } @@ -287,71 +287,71 @@ class User { new User().sayHi(); ``` -Such features are easy to remember, as they resemble that of literal objects. +Nogle muligheder er nemme at huske, da de minder om dem fra normale objekter. ## Class fields -```warn header="Old browsers may need a polyfill" -Class fields are a recent addition to the language. +```warn header="Ældre browsere kan have brug for et polyfill" +Class fields er en relativ ny feature i JavaScript. ``` -Previously, our classes only had methods. +Tidligere havde klasser kun metoder. -"Class fields" is a syntax that allows to add any properties. +"Class fields" er en syntaks der tillader os at tilføje vilkårlige egenskaber. -For instance, let's add `name` property to `class User`: +For eksempel, lad os tilføje egenskaben `name` til `class User`: ```js run class User { *!* - name = "John"; + name = "Karsten"; */!* sayHi() { - alert(`Hello, ${this.name}!`); + alert(`Hej ${this.name}!`); } } -new User().sayHi(); // Hello, John! +new User().sayHi(); // Hej Karsten! ``` -So, we just write " = " in the declaration, and that's it. +Så vi skriver simpelthen " = " i deklarationen, og det er det. -The important difference of class fields is that they are set on individual objects, not `User.prototype`: +En vigtig forskel mellem class fields og almindelige metoder er, at de er sat på individuelle objekter, ikke `User.prototype`: ```js run class User { *!* - name = "John"; + name = "Karsten"; */!* } let user = new User(); -alert(user.name); // John +alert(user.name); // Karsten alert(User.prototype.name); // undefined ``` -We can also assign values using more complex expressions and function calls: +Vi kan også tildele værdier ved hjælp af mere komplekse udtryk og funktionskald: ```js run class User { *!* - name = prompt("Name, please?", "John"); + name = prompt("Dit navn, tak?", "Karsten"); */!* } let user = new User(); -alert(user.name); // John +alert(user.name); // Karsten ``` -### Making bound methods with class fields +### Gør bundne metoder til class fields -As demonstrated in the chapter functions in JavaScript have a dynamic `this`. It depends on the context of the call. +Som demonstreret i kapitlet har funktioner i JavaScript en dynamisk `this`. Det afhænger af konteksten for kaldet. -So if an object method is passed around and called in another context, `this` won't be a reference to its object any more. +Så hvis en objektmetode bliver videregivet og kaldt i en anden kontekst, vil `this` ikke længere være en reference til objektet. -For instance, this code will show `undefined`: +For eksempel vil denne kode vise `undefined`: ```js run class Button { @@ -364,21 +364,21 @@ class Button { } } -let button = new Button("hello"); +let button = new Button("hej"); *!* setTimeout(button.click, 1000); // undefined */!* ``` -The problem is called "losing `this`". +Problemet kaldes populært at den "mister `this`" ("losing `this`"). -There are two approaches to fixing it, as discussed in the chapter : +Der er to tilgange til at fikse det, som vi diskuterede i kapitlet : -1. Pass a wrapper-function, such as `setTimeout(() => button.click(), 1000)`. -2. Bind the method to object, e.g. in the constructor. +1. Videregiv en wrapper-funktion, i stil med `setTimeout(() => button.click(), 1000)`. +2. Bind metoden til objektet, f.eks. i constructor. -Class fields provide another, quite elegant syntax: +Class fields leverer en anden, ganske elegant syntaks: ```js run class Button { @@ -392,37 +392,37 @@ class Button { */!* } -let button = new Button("hello"); +let button = new Button("hej"); -setTimeout(button.click, 1000); // hello +setTimeout(button.click, 1000); // hej ``` -The class field `click = () => {...}` is created on a per-object basis, there's a separate function for each `Button` object, with `this` inside it referencing that object. We can pass `button.click` around anywhere, and the value of `this` will always be correct. +class field `click = () => {...}` oprettes på individuelle objekter, så der er en seperat funktion for hver `Button`-objekt, med `this` inde i den, der refererer til det objekt. Vi kan overføre `button.click` hvor som helst, og værdien af `this` vil altid være korrekt. -That's especially useful in browser environment, for event listeners. +Det er især nyttigt i browser-miljøet, for event-listeners. -## Summary +## Opsummering -The basic class syntax looks like this: +Den grundlæggende syntaks for klasser ser sådan ud: ```js class MyClass { - prop = value; // property + prop = value; // egenskab (class field) constructor(...) { // constructor // ... } - method(...) {} // method + method(...) {} // metode - get something(...) {} // getter method - set something(...) {} // setter method + get something(...) {} // getter metode + set something(...) {} // setter metode - [Symbol.iterator]() {} // method with computed name (symbol here) + [Symbol.iterator]() {} // metode med beregnet navn (symbol her) // ... } ``` -`MyClass` is technically a function (the one that we provide as `constructor`), while methods, getters and setters are written to `MyClass.prototype`. +`MyClass` er teknisk set en function (den vi leverer som `constructor`), mens metoder, getters og setters skrives i `MyClass.prototype`. -In the next chapters we'll learn more about classes, including inheritance and other features. +I de næste kapitler vil vi lære mere om klasser, nedarvning og andre funktioner. diff --git a/1-js/09-classes/index.md b/1-js/09-classes/index.md index 87846ef6..70a9e4cd 100644 --- a/1-js/09-classes/index.md +++ b/1-js/09-classes/index.md @@ -1 +1 @@ -# Classes +# Klasser From eda3795e21f1934c4b5f104fe589062ddaff072d Mon Sep 17 00:00:00 2001 From: ockley Date: Sat, 7 Mar 2026 14:54:46 +0100 Subject: [PATCH 04/21] Oversat til dansk --- .../1-class-constructor-error/solution.md | 8 +- .../1-class-constructor-error/task.md | 8 +- .../source.view/index.html | 7 +- .../2-clock-class-extended/task.md | 10 +- .../animal-rabbit-extends.svg | 107 ++++- .../02-class-inheritance/article.md | 376 +++++++++--------- .../class-inheritance-rabbit-animal-2.svg | 90 ++++- .../rabbit-animal-independent-animal.svg | 63 ++- .../rabbit-animal-independent-rabbit.svg | 61 ++- 9 files changed, 521 insertions(+), 209 deletions(-) diff --git a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md index 4711e482..cd5e25d7 100644 --- a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md +++ b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md @@ -1,6 +1,6 @@ -That's because the child constructor must call `super()`. +Det er fordi at konstruktøren skal kalde `super()`. -Here's the corrected code: +Her er den tilrettede kode: ```js run class Animal { @@ -21,7 +21,7 @@ class Rabbit extends Animal { } *!* -let rabbit = new Rabbit("White Rabbit"); // ok now +let rabbit = new Rabbit("Hvid kanin"); // ok nu */!* -alert(rabbit.name); // White Rabbit +alert(rabbit.name); // Hvid kanin ``` diff --git a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md index 380a4720..827a3717 100644 --- a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md +++ b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Error creating an instance +# Fejl ved oprettelse af instans -Here's the code with `Rabbit` extending `Animal`. +Her er koden hvor `Rabbit` udvider `Animal`. -Unfortunately, `Rabbit` objects can't be created. What's wrong? Fix it. +Uheldigvis kan `Rabbit`-objekter ikke oprettes. Hvad er galt? Ret det. ```js run class Animal { @@ -24,7 +24,7 @@ class Rabbit extends Animal { } *!* -let rabbit = new Rabbit("White Rabbit"); // Error: this is not defined +let rabbit = new Rabbit("Hvid kanin"); // Fejl: this is not defined */!* alert(rabbit.name); ``` diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html index c0609858..b0c0ab45 100644 --- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html +++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html @@ -1,13 +1,12 @@ - + From d82d85f9b938b51e94142ac0205321272ced9d78 Mon Sep 17 00:00:00 2001 From: ockley Date: Fri, 20 Mar 2026 15:51:22 +0100 Subject: [PATCH 12/21] oversat til dansk --- .../1-finally-or-code-after/solution.md | 24 +- .../1-finally-or-code-after/task.md | 22 +- 1-js/10-error-handling/1-try-catch/article.md | 391 +++++++++--------- .../1-try-catch/try-catch-flow.svg | 92 ++++- 4 files changed, 309 insertions(+), 220 deletions(-) diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md index ec0dabc9..20f36734 100644 --- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md +++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md @@ -1,47 +1,47 @@ -The difference becomes obvious when we look at the code inside a function. +Forskellen bliver tydelig, når vi kigger på koden inde i en funktion. -The behavior is different if there's a "jump out" of `try...catch`. +Det er forskelligt, hvis der er et "spring ud" af `try...catch`. -For instance, when there's a `return` inside `try...catch`. The `finally` clause works in case of *any* exit from `try...catch`, even via the `return` statement: right after `try...catch` is done, but before the calling code gets the control. +For eksempel, når der er en `return` inde i `try...catch`. `finally`-klausulen virker i tilfældet af *hvilken som helst* afslutning fra `try...catch`, selv via `return`-sætningen: lige efter `try...catch` er færdig, men før den kaldende kode får kontrollen. ```js run function f() { try { alert('start'); *!* - return "result"; + return "resultat"; */!* } catch (err) { /// ... } finally { - alert('cleanup!'); + alert('oprydning!'); } } -f(); // cleanup! +f(); // oprydning! ``` -...Or when there's a `throw`, like here: +...eller hvis der er en `throw`, som her: ```js run function f() { try { alert('start'); - throw new Error("an error"); + throw new Error("en fejl"); } catch (err) { // ... - if("can't handle the error") { + if("kan ikke håndtere fejlen") { *!* throw err; */!* } } finally { - alert('cleanup!') + alert('oprydning!') } } -f(); // cleanup! +f(); // oprydning! ``` -It's `finally` that guarantees the cleanup here. If we just put the code at the end of `f`, it wouldn't run in these situations. +Det er `finally` der garanterer oprydningen her. Hvis vi bare sætter koden ved slutningen af `f`, ville den ikke køre i disse situationer. diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md index b6dc8132..c5663cba 100644 --- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md +++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md @@ -4,35 +4,35 @@ importance: 5 # Finally or just the code? -Compare the two code fragments. +Sammenlign disse to kodefragmenter. -1. The first one uses `finally` to execute the code after `try...catch`: +1. Den første bruger `finally` til at køre koden efter `try...catch`: ```js try { - work work + arbejd' arbejd' } catch (err) { - handle errors + håndter fejl } finally { *!* - cleanup the working space + ryd op på arbejdspladsen */!* } ``` -2. The second fragment puts the cleaning right after `try...catch`: +2. Den anden placerer oprydningen lige efter `try...catch`: ```js try { - work work + arbejd' arbejd' } catch (err) { - handle errors + håndter fejl } *!* - cleanup the working space + ryd op på arbejdspladsen */!* ``` -We definitely need the cleanup after the work, doesn't matter if there was an error or not. +Vi skal selvfølgelig have oprydningen efter arbejdet, uanset om der var en fejl eller ej. -Is there an advantage here in using `finally` or both code fragments are equal? If there is such an advantage, then give an example when it matters. +Er der en fordel i at bruge `finally` eller er de to kodefragmenter ens? Hvis der er en sådan fordel, så giv et eksempel på, når det betyder noget. diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index cad2e1a3..a8bf2b7b 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -1,98 +1,98 @@ -# Error handling, "try...catch" +# Håndtering af fejl, "try...catch" -No matter how great we are at programming, sometimes our scripts have errors. They may occur because of our mistakes, an unexpected user input, an erroneous server response, and for a thousand other reasons. +Uanset hvor gode vi er til programmering, så har vores scripts periodisk fejl. De kan opstå på grund af vores fejl, et uventet brugerinput, et fejlbehæftet server svar, og for tusind andre grunde. -Usually, a script "dies" (immediately stops) in case of an error, printing it to console. +Normalt dør et script (stoppes øjeblikkeligt) når en fejl opstår, og fejlen udskrives til konsollen. -But there's a syntax construct `try...catch` that allows us to "catch" errors so the script can, instead of dying, do something more reasonable. +Men der er en konstruktion `try...catch` som tillader os at "fange" fejl, så scriptet kan gøre noget mere fornuftigt end at dø. -## The "try...catch" syntax +## Syntaksen "try...catch" -The `try...catch` construct has two main blocks: `try`, and then `catch`: +Konstruktionen `try...catch` har to hovedblokke: `try`, og derefter `catch`: ```js try { - // code... + // kode... } catch (err) { - // error handling + // fejlhåndtering } ``` -It works like this: +Det virker sådan: -1. First, the code in `try {...}` is executed. -2. If there were no errors, then `catch (err)` is ignored: the execution reaches the end of `try` and goes on, skipping `catch`. -3. If an error occurs, then the `try` execution is stopped, and control flows to the beginning of `catch (err)`. The `err` variable (we can use any name for it) will contain an error object with details about what happened. +1. Først vil koden i `try {...}` blive kørt. +2. Hvis der ikke er nogen fejl, så ignoreres `catch (err)`: eksekveringen når til slutningen af `try` og går videre, springer over `catch`. +3. Hvis en fejl opstår, så stoppes `try`-eksekveringen, og kontrol flyttes til begyndelsen af `catch (err)`. Den `err`-variabel (vi kan bruge et hvilket som helst navn) vil indeholde et fejlobjekt med detaljer om, hvad der skete. ![](try-catch-flow.svg) -So, an error inside the `try {...}` block does not kill the script -- we have a chance to handle it in `catch`. +Så, hvis der sker en fejl inde i `try {...}` blokken, så dør scriptet ikke -- vi har en chance til at håndtere den i `catch`. -Let's look at some examples. +Lad os se på et par eksempler. -- An errorless example: shows `alert` `(1)` and `(2)`: +- Et eksempel uden fejl: viser `alert` `(1)` og `(2)`: ```js run try { - alert('Start of try runs'); // *!*(1) <--*/!* + alert('Start på "try runs"'); // *!*(1) <--*/!* - // ...no errors here + // ...ingen fejl her - alert('End of try runs'); // *!*(2) <--*/!* + alert('Slut på "try runs"'); // *!*(2) <--*/!* } catch (err) { - alert('Catch is ignored, because there are no errors'); // (3) + alert('Catch ignoreres fordi der ikke var fejl'); // (3) } ``` -- An example with an error: shows `(1)` and `(3)`: +- Et eksempel med en fejl: viser `(1)` og `(3)`: ```js run try { - alert('Start of try runs'); // *!*(1) <--*/!* + alert('Start på "try runs"'); // *!*(1) <--*/!* *!* - lalala; // error, variable is not defined! + lalala; // fejl, variable is not defined! */!* - alert('End of try (never reached)'); // (2) + alert('Slut på "try runs"'); // (2) } catch (err) { - alert(`Error has occurred!`); // *!*(3) <--*/!* + alert(`Der skete en fejl!`); // *!*(3) <--*/!* } ``` -````warn header="`try...catch` only works for runtime errors" -For `try...catch` to work, the code must be runnable. In other words, it should be valid JavaScript. +````warn header="`try...catch` virker kun for runtime errors" +For at `try...catch` skal virke skal koden kunne køre. Med anre ord skal det være gyldig (valid) JavaScript. -It won't work if the code is syntactically wrong, for instance it has unmatched curly braces: +Den virker ikke hvis syntaksen er forkert. For eksempel hvis der er rod med parenteser: ```js run try { {{{{{{{{{{{{ } catch (err) { - alert("The engine can't understand this code, it's invalid"); + alert("Motoren forstår ikke denne kode, den er ugyldig"); } ``` -The JavaScript engine first reads the code, and then runs it. The errors that occur on the reading phase are called "parse-time" errors and are unrecoverable (from inside that code). That's because the engine can't understand the code. +JavaScript-motoren læser koden først, og derefter kører den. De fejl, der opstår under læsningen, kaldes "parse-time" fejl og er unrecoverable (fra inde i koden). Det er fordi motoren ikke kan forstå koden. -So, `try...catch` can only handle errors that occur in valid code. Such errors are called "runtime errors" or, sometimes, "exceptions". -```` +Så, `try...catch` kan kun håndtere fejl, der opstår i gyldig kode. Sådanne fejl kaldes "runtime errors" eller, nogle gange, "exceptions". +``` -````warn header="`try...catch` works synchronously" -If an exception happens in "scheduled" code, like in `setTimeout`, then `try...catch` won't catch it: +````warn header="`try...catch` virker synkront" +Hvis en exception opstår i "planlagt" kode, som i `setTimeout`, så vil `try...catch` ikke fange den: ```js run try { @@ -100,112 +100,112 @@ try { noSuchVariable; // script will die here }, 1000); } catch (err) { - alert( "won't work" ); + alert( "det her virker ikke" ); } ``` -That's because the function itself is executed later, when the engine has already left the `try...catch` construct. +Det er fordi at selve funktionen først afvikles senere - det har motoren allerede forladt `try...catch` konstruktionen. -To catch an exception inside a scheduled function, `try...catch` must be inside that function: +For at fange en exception inde i en planlagt funktion, skal `try...catch` være inde i selve funktionen: ```js run setTimeout(function() { try { - noSuchVariable; // try...catch handles the error! + noSuchVariable; // try...catch håndterer fejlen! } catch { - alert( "error is caught here!" ); + alert( "fejlen fanges her!" ); } }, 1000); ``` ```` -## Error object +## Error objekt -When an error occurs, JavaScript generates an object containing the details about it. The object is then passed as an argument to `catch`: +Når der opstår en fejl, genererer JavaScript et objekt, der indeholder detaljerne om fejlen. Objektet sendes derefter som et argument til `catch`: ```js try { // ... -} catch (err) { // <-- the "error object", could use another word instead of err +} catch (err) { // <-- her er "error objektet", du kan sagtens bruge et andet navn istedet for err // ... } ``` -For all built-in errors, the error object has two main properties: +For alle indbyggede fejl har error objektet to hovedegenskaber: `name` -: Error name. For instance, for an undefined variable that's `"ReferenceError"`. +: Navnet på fejlen. Hvis det for eksempel er en ikke-defineret variabel, så indeholder den `"ReferenceError"`. `message` -: Textual message about error details. +: En tekst der beskriver fejlen. -There are other non-standard properties available in most environments. One of most widely used and supported is: +Der er andre ikke-standard egenskaber tilgængelige i de fleste miljøer. En af de mest brugte og understøttede er: `stack` -: Current call stack: a string with information about the sequence of nested calls that led to the error. Used for debugging purposes. +: Aktuel kaldestak: en streng med information om sekvensen af indlejrede kald, der ledte til fejlen. Bruges til fejlfinding. -For instance: +For eksempel: ```js run untrusted try { *!* - lalala; // error, variable is not defined! + lalala; // fejl, variablen er ikke defineret! */!* } catch (err) { alert(err.name); // ReferenceError alert(err.message); // lalala is not defined alert(err.stack); // ReferenceError: lalala is not defined at (...call stack) - // Can also show an error as a whole - // The error is converted to string as "name: message" + // Kan også vise en fejl som et samlet output + // Fejlen konverteres til en streng som "name: message" alert(err); // ReferenceError: lalala is not defined } ``` -## Optional "catch" binding +## Frivillig "catch" binding [recent browser=new] -If we don't need error details, `catch` may omit it: +Hvis vi ikke behøver detaljer om fejlen, kan `catch` udelade den: ```js try { // ... -} catch { // <-- without (err) +} catch { // <-- uden (err) // ... } ``` -## Using "try...catch" +## Brug af "try...catch" -Let's explore a real-life use case of `try...catch`. +Lad os udforske brugsscenarier for `try...catch`. -As we already know, JavaScript supports the [JSON.parse(str)](mdn:js/JSON/parse) method to read JSON-encoded values. +Som vi allerede ved så understøtter JavaScript metoden [JSON.parse(str)](mdn:js/JSON/parse) til at læse JSON værdier. -Usually it's used to decode data received over the network, from the server or another source. +Normalt bruges den til at afkode data der er modtaget over netværket, fra serveren eller anden kilde. -We receive it and call `JSON.parse` like this: +Vi modtager det og kalder `JSON.parse` sådan her: ```js run let json = '{"name":"John", "age": 30}'; // data from the server *!* -let user = JSON.parse(json); // convert the text representation to JS object +let user = JSON.parse(json); // konverterer tekstrepræsentation til JS-objekt */!* -// now user is an object with properties from the string +// nu er user et objekt med egenskaber fra strengen alert( user.name ); // John alert( user.age ); // 30 ``` -You can find more detailed information about JSON in the chapter. +Du kan finde mere detaljeret information om JSON i kapitlet . -**If `json` is malformed, `JSON.parse` generates an error, so the script "dies".** +**Hvis `json` indeholder fejl vil `JSON.parse` generere en fejl, så scriptet "dør".** -Should we be satisfied with that? Of course not! +Skal vi stille os tilfreds med det? Nej, selvfølgelig ikke! -This way, if something's wrong with the data, the visitor will never know that (unless they open the developer console). And people really don't like when something "just dies" without any error message. +På denne måde, hvis der er noget galt med data, vil besøgende aldrig vide det (medmindre de åbner konsollen). Og folk kan ikke li', når noget "bare dør" uden nogen fejlbesked. -Let's use `try...catch` to handle the error: +Lad os bruge `try...catch` til at håndtere fejlen: ```js run let json = "{ bad json }"; @@ -213,74 +213,74 @@ let json = "{ bad json }"; try { *!* - let user = JSON.parse(json); // <-- when an error occurs... + let user = JSON.parse(json); // <-- når en fejl opstår... */!* - alert( user.name ); // doesn't work + alert( user.name ); // virker ikke } catch (err) { *!* - // ...the execution jumps here - alert( "Our apologies, the data has errors, we'll try to request it one more time." ); + // ...hopper afviklingen her til + alert( "Desværre indeholder vores data fejl, vi vil forsøge at anmode om den en gang til." ); alert( err.name ); alert( err.message ); */!* } ``` -Here we use the `catch` block only to show the message, but we can do much more: send a new network request, suggest an alternative to the visitor, send information about the error to a logging facility, ... . All much better than just dying. +Her bruger vi kun `catch` blokken til at vise en besked, men vi kan gøre meget andet: sende et nyt netværkskald, foreslå et alternativ til besøgende, send information om fejlen til en log, ... alle muligheder der er meget bedre end bare at dø. -## Throwing our own errors +## Kaste vores egne fejl -What if `json` is syntactically correct, but doesn't have a required `name` property? +Hvad hvis `json` er syntactisk korrekt, men ikke har en påkrævet `name` egenskab? -Like this: +Som dette: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "age": 30 }'; // ufuldstændige data try { - let user = JSON.parse(json); // <-- no errors + let user = JSON.parse(json); // <-- ingen fejl *!* - alert( user.name ); // no name! + alert( user.name ); // intet navn! */!* } catch (err) { - alert( "doesn't execute" ); + alert( "afvikles ikke" ); } ``` -Here `JSON.parse` runs normally, but the absence of `name` is actually an error for us. +Her kører `JSON.parse` normalt, men fraværet af `name` er faktisk en fejl for os. -To unify error handling, we'll use the `throw` operator. +For at ensrette fejlhåndteringen, vil vi bruge `throw` operatoren. ### "Throw" operator -The `throw` operator generates an error. +Operatoren `throw` genererer en fejl. -The syntax is: +Syntaksen er: ```js throw ``` -Technically, we can use anything as an error object. That may be even a primitive, like a number or a string, but it's better to use objects, preferably with `name` and `message` properties (to stay somewhat compatible with built-in errors). +Teknisk set kan vi kaste hvad som helst som et error objekt. Det kan endda være en primitiv, som et tal eller en streng, men det er bedre at bruge objekter, især med `name` og `message` egenskaber (for at forblive nogenlunde kompatibel med de indbyggede fejl). -JavaScript has many built-in constructors for standard errors: `Error`, `SyntaxError`, `ReferenceError`, `TypeError` and others. We can use them to create error objects as well. +JavaScript har mange indbyggede konstruktører for standardfejl: `Error`, `SyntaxError`, `ReferenceError`, `TypeError` og andre. Vi kan bruge dem til at oprette fejlobjekter. -Their syntax is: +Deres syntaks er: ```js let error = new Error(message); -// or +// eller let error = new SyntaxError(message); let error = new ReferenceError(message); // ... ``` -For built-in errors (not for any objects, just for errors), the `name` property is exactly the name of the constructor. And `message` is taken from the argument. +For indbyggede fejl (ikke for objekter generelt, kun for fejl) er `name` egenskaben præcis det samme som navnet på konstruktøren, og `message` er taget fra argumentet. -For instance: +For eksempel: ```js run let error = new Error("Things happen o_O"); @@ -289,7 +289,7 @@ alert(error.name); // Error alert(error.message); // Things happen o_O ``` -Let's see what kind of error `JSON.parse` generates: +Lad os se hvilken fejl `JSON.parse` genererer, når den ikke kan læse data: ```js run try { @@ -302,14 +302,14 @@ try { } ``` -As we can see, that's a `SyntaxError`. +Som vi kan se er det en `SyntaxError`. -And in our case, the absence of `name` is an error, as users must have a `name`. +Og i vores tilfælde er fraværet af `name` en fejl, da brugere skal have et `name`. -So let's throw it: +Så lad os kaste den fejl, og håndtere den i `catch`: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "age": 30 }'; // ufuldstændige data try { @@ -317,55 +317,55 @@ try { if (!user.name) { *!* - throw new SyntaxError("Incomplete data: no name"); // (*) + throw new SyntaxError("Ufuldstændige data: name mangler"); // (*) */!* } alert( user.name ); } catch (err) { - alert( "JSON Error: " + err.message ); // JSON Error: Incomplete data: no name + alert( "JSON Error: " + err.message ); // JSON Error: Ufuldstændige data: name mangler } ``` -In the line `(*)`, the `throw` operator generates a `SyntaxError` with the given `message`, the same way as JavaScript would generate it itself. The execution of `try` immediately stops and the control flow jumps into `catch`. +I linjen med `(*)`, genererer `throw` operatoren en `SyntaxError` med den angivne `message`, på samme måde som JavaScript ville generere det selv. Afviklingen af `try` stopper med det samme og kontrollen af flower overgår til `catch`. -Now `catch` became a single place for all error handling: both for `JSON.parse` and other cases. +Nu bliver `catch` det eneste sted for al fejlhåndtering: både for `JSON.parse` og for andre scenarier. ## Rethrowing -In the example above we use `try...catch` to handle incorrect data. But is it possible that *another unexpected error* occurs within the `try {...}` block? Like a programming error (variable is not defined) or something else, not just this "incorrect data" thing. +I eksemplet ovenfor bruger vi `try...catch` til at håndtere forkert data i JSON filen. Men er det muligt at *en anden uventet fejl* opstår inden for `try {...}` blokken? Som en programmeringsfejl (variabel er ikke defineret) eller noget andet, ikke bare denne "forkerte data" ting. -For example: +For eksempel: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "age": 30 }'; // ufuldstændige data try { - user = JSON.parse(json); // <-- forgot to put "let" before user + user = JSON.parse(json); // <-- glemte at putte "let" foran user // ... } catch (err) { - alert("JSON Error: " + err); // JSON Error: ReferenceError: user is not defined - // (no JSON Error actually) + alert("JSON Fejl: " + err); // JSON Fejl: ReferenceError: user is not defined + // (faktisk ikke en JSON fejl) } ``` -Of course, everything's possible! Programmers do make mistakes. Even in open-source utilities used by millions for decades -- suddenly a bug may be discovered that leads to terrible hacks. +Selvfølgelig, alt er muligt! Programmører laver fejl. Selv i open-source værktøjer der er brugt af millioner i årtier -- pludselig kan en fejl blive opdaget, der fører til frygtelige hacks. -In our case, `try...catch` is placed to catch "incorrect data" errors. But by its nature, `catch` gets *all* errors from `try`. Here it gets an unexpected error, but still shows the same `"JSON Error"` message. That's wrong and also makes the code more difficult to debug. +I vores tilfælde, `try...catch` er placeret for at fange "forkerte data" fejl. Men selve konstrulktionen dikterer at `catch` får *alle* fejl fra `try`. Her får det en uventet fejl, men viser stadig den samme `"JSON Error"` besked. Det er forkert og gør også koden sværere at debugge. -To avoid such problems, we can employ the "rethrowing" technique. The rule is simple: +For at undgå sådanne problemer, kan vi bruge "rethrowing" teknikken. Reglen er simpel: -**Catch should only process errors that it knows and "rethrow" all others.** +**Catch skal kun behandle fejl, den kender, og "rethrow" alle andre.** -The "rethrowing" technique can be explained in more detail as: +Teknikken "rethrowing" kan forklares lidt mere detaljeret som: -1. Catch gets all errors. -2. In the `catch (err) {...}` block we analyze the error object `err`. -3. If we don't know how to handle it, we do `throw err`. +1. Opfang alle fejl. +2. I blokken `catch (err) {...}` analyserer vi error objektet. +3. Hvis vi ikke ved, hvordan vi skal håndtere den, kaster vi den med `throw err`. -Usually, we can check the error type using the `instanceof` operator: +Normalt kan vi tjekke fejltypen ved hjælp af `instanceof` operatoren: ```js run try { @@ -374,27 +374,27 @@ try { *!* if (err instanceof ReferenceError) { */!* - alert('ReferenceError'); // "ReferenceError" for accessing an undefined variable + alert('ReferenceError'); // "ReferenceError" for at tilgå en variabel der er undefineret } } ``` -We can also get the error class name from `err.name` property. All native errors have it. Another option is to read `err.constructor.name`. +Vi kan også få fejlens navn fra `err.name` egenskaben. Alle indbyggede fejl har den. En anden option er at læse `err.constructor.name`. -In the code below, we use rethrowing so that `catch` only handles `SyntaxError`: +I koden nedenfor, vi bruger rethrowing så `catch` kun håndterer `SyntaxError`: ```js run -let json = '{ "age": 30 }'; // incomplete data +let json = '{ "age": 30 }'; // ufuldstændige data try { let user = JSON.parse(json); if (!user.name) { - throw new SyntaxError("Incomplete data: no name"); + throw new SyntaxError("Ufuldstændige data: name mangler"); } *!* - blabla(); // unexpected error + blabla(); // uventet fejl */!* alert( user.name ); @@ -403,7 +403,7 @@ try { *!* if (err instanceof SyntaxError) { - alert( "JSON Error: " + err.message ); + alert( "JSON fejl: " + err.message ); } else { throw err; // rethrow (*) } @@ -412,11 +412,11 @@ try { } ``` -The error throwing on line `(*)` from inside `catch` block "falls out" of `try...catch` and can be either caught by an outer `try...catch` construct (if it exists), or it kills the script. +Fejlkastningen på linjen med `(*)` inde i `catch` blokken "falder ud" af `try...catch` og kan enten blive fanget af en ydre `try...catch` construct (hvis den eksisterer), eller også dør scriptet. -So the `catch` block actually handles only errors that it knows how to deal with and "skips" all others. +Så `catch` blokken håndterer faktisk kun fejl, den ved hvordan den skal håndtere, og "dropper" alle andre. -The example below demonstrates how such errors can be caught by one more level of `try...catch`: +Eksemplet nedenfor viser, hvordan sådanne fejl kan blive fanget af et ekstra niveau af `try...catch`: ```js run function readData() { @@ -425,13 +425,13 @@ function readData() { try { // ... *!* - blabla(); // error! + blabla(); // fejl! */!* } catch (err) { // ... if (!(err instanceof SyntaxError)) { *!* - throw err; // rethrow (don't know how to deal with it) + throw err; // rethrow (ved ikke hvordan man skal håndtere det) */!* } } @@ -441,42 +441,42 @@ try { readData(); } catch (err) { *!* - alert( "External catch got: " + err ); // caught it! + alert( "Ydre catch modtog: " + err ); // fangede den! */!* } ``` -Here `readData` only knows how to handle `SyntaxError`, while the outer `try...catch` knows how to handle everything. +Her ved `readData` kun hvordan den skal håndtere `SyntaxError`, mens den ydre `try...catch` ved hvordan den skal håndtere alt. ## try...catch...finally -Wait, that's not all. +vent, der er mere endnu. -The `try...catch` construct may have one more code clause: `finally`. +Konstruktionen `try...catch` har en såkaldt klausul mere, nemlig `finally`. -If it exists, it runs in all cases: +Hvis den eksisterer, kører den i alle tilfælde: -- after `try`, if there were no errors, -- after `catch`, if there were errors. +- efter `try`, hvis der ikke var nogen fejl, +- efter `catch`, hvis der var fejl. -The extended syntax looks like this: +Den udvidede syntaks ser sådan ud: ```js *!*try*/!* { - ... try to execute the code ... + ... prøv at afvikle noget kode ... } *!*catch*/!* (err) { - ... handle errors ... + ... håndter fejl ... } *!*finally*/!* { - ... execute always ... + ... kører altid til sidst ... } ``` -Try running this code: +Prøv at køre denne kode for at se, hvordan det fungerer: ```js run try { alert( 'try' ); - if (confirm('Make an error?')) BAD_CODE(); + if (confirm('Skal der laves en fejl?')) BAD_CODE(); } catch (err) { alert( 'catch' ); } finally { @@ -484,27 +484,27 @@ try { } ``` -The code has two ways of execution: +Koden har to måder at blive afviklet på: -1. If you answer "Yes" to "Make an error?", then `try -> catch -> finally`. -2. If you say "No", then `try -> finally`. +1. Hvis du svarer "Ja" til "Skal der laves en fejl?", så `try -> catch -> finally`. +2. Hvis du svarer "Nej", så `try -> finally`. -The `finally` clause is often used when we start doing something and want to finalize it in any case of outcome. +Klausulen `finally` bruges ofte, når vi starter noget og vil have det afsluttet uanset resultatet. -For instance, we want to measure the time that a Fibonacci numbers function `fib(n)` takes. Naturally, we can start measuring before it runs and finish afterwards. But what if there's an error during the function call? In particular, the implementation of `fib(n)` in the code below returns an error for negative or non-integer numbers. +For eksempel, vi vil måle tiden, det tager at køre en Fibonacci tal funktion `fib(n)`. Naturligvis kan vi starte måling før den kører og afslutte efterfølgende. Men hvad hvis der er en fejl under funktionskaldet? Især implementationen af `fib(n)` i koden nedenfor returnerer en fejl for negative eller ikke-heltalstal. -The `finally` clause is a great place to finish the measurements no matter what. +`finally` klausulen er et godt sted at afslutte målingerne uanset hvad. -Here `finally` guarantees that the time will be measured correctly in both situations -- in case of a successful execution of `fib` and in case of an error in it: +Her garanterer `finally` at tiden vil blive målt korrekt i begge situationer -- i tilfælde af en succesfuld udførelse af `fib` og i tilfælde af en fejl i den: ```js run -let num = +prompt("Enter a positive integer number?", 35) +let num = +prompt("Skriv et positivt heltal?", 35) let diff, result; function fib(n) { if (n < 0 || Math.trunc(n) != n) { - throw new Error("Must not be negative, and also an integer."); + throw new Error("Tallet må ikke være negativt, og det skal være et heltal."); } return n <= 1 ? n : fib(n - 1) + fib(n - 2); } @@ -521,26 +521,26 @@ try { } */!* -alert(result || "error occurred"); +alert(result || "der skete en fejl"); -alert( `execution took ${diff}ms` ); +alert( `udførelsen tog ${diff}ms` ); ``` -You can check by running the code with entering `35` into `prompt` -- it executes normally, `finally` after `try`. And then enter `-1` -- there will be an immediate error, and the execution will take `0ms`. Both measurements are done correctly. +Du kan nu køre koden med at indtaste `35` i `prompt` -- den kører normalt, `finally` efter `try`. Prøv bagefter at indtaste `-1` -- der vil umiddelbart være en fejl, og udførelsen vil tage `0ms`. Begge målinger er udført korrekt. -In other words, the function may finish with `return` or `throw`, that doesn't matter. The `finally` clause executes in both cases. +Med andre ord, funktionen kan slutte med `return` eller `throw`, det spiller ingen rolle. Klausulen `finally` udføres i begge tilfælde. -```smart header="Variables are local inside `try...catch...finally`" -Please note that `result` and `diff` variables in the code above are declared *before* `try...catch`. +```smart header="Variable er lokale inde i `try...catch...finally`" +Bemærk at `result` og `diff` variablene i koden ovenfor er deklareret *før* `try...catch`. -Otherwise, if we declared `let` in `try` block, it would only be visible inside of it. +Ellers, hvis vi deklarerede `let` i `try` blokken, ville den kun være synlig inden for den. ``` -````smart header="`finally` and `return`" -The `finally` clause works for *any* exit from `try...catch`. That includes an explicit `return`. +````smart header="`finally` og `return`" +Klausulen `finally` virker for *alle* udgange fra `try...catch`. Det indbefatter også en eksplicit `return`. -In the example below, there's a `return` in `try`. In this case, `finally` is executed just before the control returns to the outer code. +I eksemplet nedenfor, er der en `return` i `try`. I dette tilfælde, udføres `finally` lige før kontrol returnerer til den ydre kode. ```js run function func() { @@ -559,40 +559,40 @@ function func() { } } -alert( func() ); // first works alert from finally, and then this one +alert( func() ); // først kommer alert fra finally, og derefter kommer denne der kalder func() ``` ```` ````smart header="`try...finally`" -The `try...finally` construct, without `catch` clause, is also useful. We apply it when we don't want to handle errors here (let them fall through), but want to be sure that processes that we started are finalized. +Konstruktionen `try...finally` uden klausulen `catch` kan også være brugbar. Den bruger vi, hvis vi ikke vil håndtere fejl her (lad dem falde gennem), men vil være sikker på, at processer, vi har startet, bliver afsluttet. ```js function func() { - // start doing something that needs completion (like measurements) + // start noget der skal afsluttes (som målinger, eller en databaseforbindelse, eller noget andet) try { // ... } finally { - // complete that thing even if all dies + // førdiggør eller ryd op lige meget om det fejler eller ej } } ``` -In the code above, an error inside `try` always falls out, because there's no `catch`. But `finally` works before the execution flow leaves the function. +I koden ovenfor vil en fejl inde `try` altid falde ud, fordi der ikke er en `catch`. Men `finally` virker før afviklingsflowet forlader funktionen. ```` ## Global catch -```warn header="Environment-specific" -The information from this section is not a part of the core JavaScript. +```warn header="Miljøspecifikt" +Informationen i denne sektion er ikke en del af selve JavaScript sproget. ``` -Let's imagine we've got a fatal error outside of `try...catch`, and the script died. Like a programming error or some other terrible thing. +Lad os forestille os, at vi får en fatal fejl uden for `try...catch`, og scriptet dør. Som en programmeringsfejl eller noget andet skrækkeligt. -Is there a way to react on such occurrences? We may want to log the error, show something to the user (normally they don't see error messages), etc. +Er der en måde at reagere på sådanne tilfælde? Vi vil måske logge fejlen, vise noget til brugeren (normalt ser de ikke fejlbeskeder), etc. -There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.js has [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to the special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property, that will run in case of an uncaught error. +Der er ingen i specifikationen, men miljøer ofte leverer det, fordi det er virkelig nyttigt. For eksempel har Node.js [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) for det. Og i browseren kan vi tildele en funktion til den specielle [window.onerror](mdn:api/GlobalEventHandlers/onerror) egenskab, som vil køre i tilfælde af en ikke-fanget fejl. -The syntax: +Syntaksen er: ```js window.onerror = function(message, url, line, col, error) { @@ -601,18 +601,18 @@ window.onerror = function(message, url, line, col, error) { ``` `message` -: Error message. +: Fejlmeddelelsen. `url` -: URL of the script where error happened. +: URL for det script hvor fejlen opstod. `line`, `col` -: Line and column numbers where error happened. +: Linje og kolonne numre hvor fejlen opstod. `error` -: Error object. +: Error objekt. -For instance: +For eksempel, denne kode har en fejl, og den vil blive fanget af `window.onerror`: ```html run untrusted refresh height=1 ``` -The role of the global handler `window.onerror` is usually not to recover the script execution -- that's probably impossible in case of programming errors, but to send the error message to developers. - -There are also web-services that provide error-logging for such cases, like or . +Rollen for den globale håndtering med `window.onerror` er normalt ikke for at genskabe scripteksekveringen -- det er sandsynligvis umuligt i tilfælde af programmeringsfejl, men for at sende fejlmeddelelsen til udviklerne. -They work like this: +Der er også web-tjenester, der leverer fejllogning for sådanne tilfælde, som eller . -1. We register at the service and get a piece of JS (or a script URL) from them to insert on pages. -2. That JS script sets a custom `window.onerror` function. -3. When an error occurs, it sends a network request about it to the service. -4. We can log in to the service web interface and see errors. +De virker sådan her: +1.Vi registrerer os hos services og får et stykke JS-kode (eller en URL til et script) fra dem til at indsætte på sider. +2. Dette JS-script sætter en brugerdefineret `window.onerror` funktion. +3. Når der sker en fejl, sender den en network request omkring det til tjenesten. +4. Vi kan så logge ind på tjenestens webinterface og se fejl. -## Summary +## Opsummering -The `try...catch` construct allows to handle runtime errors. It literally allows to "try" running the code and "catch" errors that may occur in it. +Konstruktionen `try...catch` tillade os at håndtere runtime-fejl. Det tillader os bogstaveligt talt at "prøve" at køre koden og "fange" fejl, der kan opstå i den. -The syntax is: +Syntaksen er: ```js try { - // run this code + // kør denne kode } catch (err) { - // if an error happened, then jump here - // err is the error object + // hvis der sker en fejl, så hop hertil + // err er et objekt der indeholder fejlinformationen } finally { - // do in any case after try/catch + // gør dette uanset om der sker en fejl eller ej } ``` -There may be no `catch` section or no `finally`, so shorter constructs `try...catch` and `try...finally` are also valid. +Der behøver ikke at være en `catch` klausul eller en `finally` klausul, så kortere konstruktioner `try...catch` og `try...finally` er også gyldige. -Error objects have following properties: +Error objekter har følgende egenskaber: -- `message` -- the human-readable error message. -- `name` -- the string with error name (error constructor name). -- `stack` (non-standard, but well-supported) -- the stack at the moment of error creation. +- `message` -- fejlmeddelelsen. +- `name` -- strengen med fejlnavnet (konstruktoren navn). +- `stack` (ikke-standard, men ret udbredt) -- stakken ved øjeblikket for fejl oprettelsen. -If an error object is not needed, we can omit it by using `catch {` instead of `catch (err) {`. +Hvis vi ikke behøver et error object, kan du udelade det ved at bruge `catch {` i stedet for `catch (err) {`. -We can also generate our own errors using the `throw` operator. Technically, the argument of `throw` can be anything, but usually it's an error object inheriting from the built-in `Error` class. More on extending errors in the next chapter. +Vi kan også generere vores egne fejl ved hjælp af `throw` operatoren. Teknisk set kan argumentet for `throw` være hvad som helst, men normalt er det et error object, der nedarver fra den indbyggede `Error` klasse. Mere om at udvide fejl i næste kapitel. -*Rethrowing* is a very important pattern of error handling: a `catch` block usually expects and knows how to handle the particular error type, so it should rethrow errors it doesn't know. +*Rethrowing* er en meget vigtig mønster for fejlhåndtering: en `catch` blok forventes typisk at vide, hvordan den skal håndtere den specifikke fejltype, så den bør kaste fejlen igen, hvis den ikke kender til den. -Even if we don't have `try...catch`, most environments allow us to setup a "global" error handler to catch errors that "fall out". In-browser, that's `window.onerror`. +Selv hvis vi ikke har `try...catch`, tillader de fleste miljøer os at opsætte en "global" fejlhåndtering for at fange fejl, der "falder ud". I browseren er det `window.onerror`. diff --git a/1-js/10-error-handling/1-try-catch/try-catch-flow.svg b/1-js/10-error-handling/1-try-catch/try-catch-flow.svg index 2c0d7134..336936c3 100644 --- a/1-js/10-error-handling/1-try-catch/try-catch-flow.svg +++ b/1-js/10-error-handling/1-try-catch/try-catch-flow.svg @@ -1 +1,91 @@ -BeginNo ErrorsAn error occured in the codeIgnore catch blockIgnore the rest of tryExecute catch blocktry { }// code... \ No newline at end of file + + + + + + + + + + + + Start + + + + + + + + + + + + + Ingen fejl + + + + + + En fejl skete i koden + + + + + + + Ignorer catch blok + + + Ignorer resten af try + + + Eksekver catch blokken + + + try { + + } + + + // code... + + + + \ No newline at end of file From e284bdb9ed9a97e6e7324614955aeb72fdc04d65 Mon Sep 17 00:00:00 2001 From: ockley Date: Fri, 20 Mar 2026 16:54:05 +0100 Subject: [PATCH 13/21] ovesat til dansk --- .../1-format-error/solution.md | 4 +- .../2-custom-errors/1-format-error/task.md | 14 +- .../2-custom-errors/article.md | 148 +++++++++--------- 1-js/10-error-handling/index.md | 2 +- 4 files changed, 84 insertions(+), 84 deletions(-) diff --git a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md index 754e68f9..57109386 100644 --- a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md +++ b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md @@ -6,9 +6,9 @@ class FormatError extends SyntaxError { } } -let err = new FormatError("formatting error"); +let err = new FormatError("formattingsfejl"); -alert( err.message ); // formatting error +alert( err.message ); // formatteringsfejl alert( err.name ); // FormatError alert( err.stack ); // stack diff --git a/1-js/10-error-handling/2-custom-errors/1-format-error/task.md b/1-js/10-error-handling/2-custom-errors/1-format-error/task.md index 2c8e910f..8886e2cb 100644 --- a/1-js/10-error-handling/2-custom-errors/1-format-error/task.md +++ b/1-js/10-error-handling/2-custom-errors/1-format-error/task.md @@ -2,21 +2,21 @@ importance: 5 --- -# Inherit from SyntaxError +# Nedarv fra SyntaxError -Create a class `FormatError` that inherits from the built-in `SyntaxError` class. +Opret en klasse `FormatError` som nedarver fra den indbyggede `SyntaxError`-klasse. -It should support `message`, `name` and `stack` properties. +Den bør understøtte `message`, `name` og `stack` egenskaber. -Usage example: +Brugseksempel: ```js -let err = new FormatError("formatting error"); +let err = new FormatError("formatteringsfejl"); -alert( err.message ); // formatting error +alert( err.message ); // formatteringsfejl alert( err.name ); // FormatError alert( err.stack ); // stack alert( err instanceof FormatError ); // true -alert( err instanceof SyntaxError ); // true (because inherits from SyntaxError) +alert( err instanceof SyntaxError ); // true (fordi den nedarver fra SyntaxError) ``` diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md index d28b0743..40531977 100644 --- a/1-js/10-error-handling/2-custom-errors/article.md +++ b/1-js/10-error-handling/2-custom-errors/article.md @@ -1,42 +1,42 @@ -# Custom errors, extending Error +# Brugerdefinerede fejl, udvidelse af Error -When we develop something, we often need our own error classes to reflect specific things that may go wrong in our tasks. For errors in network operations we may need `HttpError`, for database operations `DbError`, for searching operations `NotFoundError` and so on. +Når vi udvikler noget, har vi ofte brug for egne fejlklasser til at reflektere specifikke ting, der kan gå galt i vores opgaver. For fejl i netværksoperationer kan vi have brug for `HttpError`, for databaseoperationer `DbError`, for søgeoperationer `NotFoundError` og så videre. -Our errors should support basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have a `statusCode` property with a value like `404` or `403` or `500`. +Vores fejl bør understøtte grundlæggende fejl egenskaber som `message`, `name` og meget gerne `stack`. Men de kan også have andre egenskaber af deres egen type, f.eks. `HttpError` objekter kan have en `statusCode` egenskab med en værdi som `404` eller `403` eller `500`. -JavaScript allows to use `throw` with any argument, so technically our custom error classes don't need to inherit from `Error`. But if we inherit, then it becomes possible to use `obj instanceof Error` to identify error objects. So it's better to inherit from it. +JavaScript tillader at bruge `throw` med ethvert argument, så teknisk set behøver vores custom error klasser ikke at arve fra `Error`. Men hvis vi arver, så bliver det muligt at bruge `obj instanceof Error` til at identificere fejl objekter. Så det er bedre at arve fra den. -As the application grows, our own errors naturally form a hierarchy. For instance, `HttpTimeoutError` may inherit from `HttpError`, and so on. +Efterhånden som applikationen vokser, vil vores egne fejl naturligvis danne en hierarki. For eksempel kan `HttpTimeoutError` arve fra `HttpError`, og så videre. -## Extending Error +## Udvidelse af Error -As an example, let's consider a function `readUser(json)` that should read JSON with user data. +Som et eksempel, lad os overveje en funktion `readUser(json)` som skal læse JSON med brugerdata. -Here's an example of how a valid `json` may look: +Her er et eksempel på, hvordan et gyldigt `json` kan se ud: ```js let json = `{ "name": "John", "age": 30 }`; ``` -Internally, we'll use `JSON.parse`. If it receives malformed `json`, then it throws `SyntaxError`. But even if `json` is syntactically correct, that doesn't mean that it's a valid user, right? It may miss the necessary data. For instance, it may not have `name` and `age` properties that are essential for our users. +Internt bruger vi `JSON.parse`. Hvis den modtager fejlformateret `json`, så kaster den `SyntaxError`. Men selv hvis `json` er syntaktisk korrekt, betyder det jo ikke nødvendigvis, at det er en gyldig bruger? Det kan mangle de nødvendige data. For eksempel kan det ikke have `name` og `age` egenskaber, som er afgørende for vores brugere. -Our function `readUser(json)` will not only read JSON, but check ("validate") the data. If there are no required fields, or the format is wrong, then that's an error. And that's not a `SyntaxError`, because the data is syntactically correct, but another kind of error. We'll call it `ValidationError` and create a class for it. An error of that kind should also carry the information about the offending field. +Vores funktion `readUser(json)` vil ikke kun læse JSON, men også tjekke ("validere") dataene. Hvis der mangler at blive udfyldt påkrævede felter, eller det er formatet er forkert, så er det en fejl. Og det er ikke en `SyntaxError`, fordi dataene er syntaktisk korrekte, men en anden type af fejl. Vi vil kalde det `ValidationError` og oprette en klasse til det. En fejl af denne type bør også bære informationen om det fejlbehagende felt. -Our `ValidationError` class should inherit from the `Error` class. +Vores `ValidationError` klasse bør arve fra `Error` klassen. -The `Error` class is built-in, but here's its approximate code so we can understand what we're extending: +Klassen `Error` er indbygget, men her er dens omtrentlige kode, så vi kan forstå, hvad vi udvider: ```js -// The "pseudocode" for the built-in Error class defined by JavaScript itself +// "pseudocode" for den indbyggede Error klasse defineret af JavaScript selv class Error { constructor(message) { this.message = message; - this.name = "Error"; // (different names for different built-in error classes) - this.stack = ; // non-standard, but most environments support it + this.name = "Error"; // (forskellige navne for forskellige indbyggede fejltyper) + this.stack = ; // ikke-standard, men de fleste miljøer understøtter det } } ``` -Now let's inherit `ValidationError` from it and try it in action: +Lad nu `ValidationError` udvide denne `Error` og prøve at bruge den: ```js run *!* @@ -49,23 +49,23 @@ class ValidationError extends Error { } function test() { - throw new ValidationError("Whoops!"); + throw new ValidationError("Ups!"); } try { test(); } catch(err) { - alert(err.message); // Whoops! + alert(err.message); // Ups! alert(err.name); // ValidationError - alert(err.stack); // a list of nested calls with line numbers for each + alert(err.stack); // en liste af indlejrede kald med linjenumre for hvor fejlen opstod } ``` -Please note: in the line `(1)` we call the parent constructor. JavaScript requires us to call `super` in the child constructor, so that's obligatory. The parent constructor sets the `message` property. +Bemærk: i linjen `(1)` kalder vi 'parent constructor'. JavaScript kræver at vi kalder `super` i 'child constructor', så det er obligatorisk. Forældrekonstruktøren sætter `message` egenskaben. -The parent constructor also sets the `name` property to `"Error"`, so in the line `(2)` we reset it to the right value. +Forældrekonstruktøren sætter også `name` egenskaben til `"Error"`, så i linjen `(2)` nulstiller vi den til den rigtige værdi. -Let's try to use it in `readUser(json)`: +Lad os prøve at bruge den i `readUser(json)`: ```js run class ValidationError extends Error { @@ -80,52 +80,52 @@ function readUser(json) { let user = JSON.parse(json); if (!user.age) { - throw new ValidationError("No field: age"); + throw new ValidationError("Mangler feltet: age"); } if (!user.name) { - throw new ValidationError("No field: name"); + throw new ValidationError("Mangler feltet: name"); } return user; } -// Working example with try..catch +// Eksempel med try..catch try { let user = readUser('{ "age": 25 }'); } catch (err) { if (err instanceof ValidationError) { *!* - alert("Invalid data: " + err.message); // Invalid data: No field: name + alert("Ugyldige data: " + err.message); // Ugyldige data: Mangler feltet: name */!* } else if (err instanceof SyntaxError) { // (*) - alert("JSON Syntax Error: " + err.message); + alert("JSON Syntaksfejl: " + err.message); } else { - throw err; // unknown error, rethrow it (**) + throw err; // ukendt fejl, kast den videre (**) } } ``` -The `try..catch` block in the code above handles both our `ValidationError` and the built-in `SyntaxError` from `JSON.parse`. +Blokken `try..catch` i koden ovenfor åndterer både vores `ValidationError` og den indbyggede `SyntaxError` fra `JSON.parse`. -Please take a look at how we use `instanceof` to check for the specific error type in the line `(*)`. +Se hvordan vi gør brug af `instanceof` til at tjekke for den specifikke fejltype i linjen `(*)`. -We could also look at `err.name`, like this: +Vi kan også kigge på `err.name`, sådan her: ```js // ... -// instead of (err instanceof SyntaxError) +// i stedet for (err instanceof SyntaxError) } else if (err.name == "SyntaxError") { // (*) // ... ``` -The `instanceof` version is much better, because in the future we are going to extend `ValidationError`, make subtypes of it, like `PropertyRequiredError`. And `instanceof` check will continue to work for new inheriting classes. So that's future-proof. +`instanceof` versionen er meget bedre, fordi vi i fremtiden måske vil udvide `ValidationError`, lave undertyper af den i stil med `PropertyRequiredError`. Et tjek med `instanceof` vil stadig virke for nedarvede klasser. På den måde er det fremtidssikret. -Also it's important that if `catch` meets an unknown error, then it rethrows it in the line `(**)`. The `catch` block only knows how to handle validation and syntax errors, other kinds (caused by a typo in the code or other unknown reasons) should fall through. +Det er også vigtigt, at hvis `catch` møder en ukendt fejl, så kaster den den videre i linjen `(**)`. Denne `catch` blok ved kun hvordan vi håndterer validerings- og syntaksfejl. Alt andet (sket ved en fejl i koden eller andre ukendte årsager) skal falde igennem. -## Further inheritance +## Videre nedarvning -The `ValidationError` class is very generic. Many things may go wrong. The property may be absent or it may be in a wrong format (like a string value for `age` instead of a number). Let's make a more concrete class `PropertyRequiredError`, exactly for absent properties. It will carry additional information about the property that's missing. +Klassen `ValidationError` er meget generisk - mange ting kan gå galt. Egenskaben kan mangle eller den kan være i et forkert format (som en strengværdi for `age` i stedet for et tal). Lad os lave en mere konkret klasse `PropertyRequiredError`, præcist til at håndtere manglende egenskaber. Den vil bære yderligere information om den egenskab, der mangler. ```js run class ValidationError extends Error { @@ -138,7 +138,7 @@ class ValidationError extends Error { *!* class PropertyRequiredError extends ValidationError { constructor(property) { - super("No property: " + property); + super("Mangler egenskab: " + property); this.name = "PropertyRequiredError"; this.property = property; } @@ -159,32 +159,32 @@ function readUser(json) { return user; } -// Working example with try..catch +// Eksempel med try..catch try { let user = readUser('{ "age": 25 }'); } catch (err) { if (err instanceof ValidationError) { *!* - alert("Invalid data: " + err.message); // Invalid data: No property: name + alert("Ugyldige data: " + err.message); // Ugyldige data: Mangler egenskab: name alert(err.name); // PropertyRequiredError alert(err.property); // name */!* } else if (err instanceof SyntaxError) { - alert("JSON Syntax Error: " + err.message); + alert("JSON Syntaksfejl: " + err.message); } else { - throw err; // unknown error, rethrow it + throw err; // ukendt fejl, kast den videre } } ``` -The new class `PropertyRequiredError` is easy to use: we only need to pass the property name: `new PropertyRequiredError(property)`. The human-readable `message` is generated by the constructor. +Den nye klasse `PropertyRequiredError` er nem at bruge: vi behøver bare at videregive egenskabens navn: `new PropertyRequiredError(property)`. Den læsevenlige `message` bliver skabt i konstruktøren. -Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name = ` in every custom error class. We can avoid it by making our own "basic error" class that assigns `this.name = this.constructor.name`. And then inherit all our custom errors from it. +Bemærk at `this.name` in `PropertyRequiredError` constructor er igen tildelt manuelt. Det kan blive en smule besværligt -- at tildele `this.name = ` i hver custom error klasse. Vi kan undgå det ved at lave vores egen "basic error" klasse, der tildele `this.name = this.constructor.name`. Og så nedarve alle vores custom errors fra den. -Let's call it `MyError`. +Lad os kalde det `MyError`. -Here's the code with `MyError` and other custom error classes, simplified: +Her er koden med `MyError` og andre custom error klasser, forenklet: ```js run class MyError extends Error { @@ -200,56 +200,56 @@ class ValidationError extends MyError { } class PropertyRequiredError extends ValidationError { constructor(property) { - super("No property: " + property); + super("Ingen egenskab: " + property); this.property = property; } } -// name is correct +// name er korrekt indstillet af MyError alert( new PropertyRequiredError("field").name ); // PropertyRequiredError ``` -Now custom errors are much shorter, especially `ValidationError`, as we got rid of the `"this.name = ..."` line in the constructor. +Nu er brugerdefinerede fejl meget kortere, især `ValidationError`, da vi har fjernet linjen `"this.name = ..."` i constructor. -## Wrapping exceptions +## Indpakning af undtagelser (expeptions) -The purpose of the function `readUser` in the code above is "to read the user data". There may occur different kinds of errors in the process. Right now we have `SyntaxError` and `ValidationError`, but in the future `readUser` function may grow and probably generate other kinds of errors. +Meningen med funktionen `readUser` i koden ovenfor er "at læse brugerdata". Der kan opstå forskellige slags fejl i den proces. Som det er nu har vi `SyntaxError` og `ValidationError`, men i en fremtidig `readUser` funktion kan det vokse og måske generere andre typer fejl. -The code which calls `readUser` should handle these errors. Right now it uses multiple `if`s in the `catch` block, that check the class and handle known errors and rethrow the unknown ones. +Koden der kalder `readUser` bør håndtere disse fejl. Lige nu bruger den flere `if` inde i `catch` blokken, der tjekker klassen og håndterer kendte fejl og kaster de ukendte videre. -The scheme is like this: +Skemaet er sådan her: ```js try { ... - readUser() // the potential error source + readUser() // den potentielle fejlkilde ... } catch (err) { if (err instanceof ValidationError) { - // handle validation errors + // håndter valideringsfejl } else if (err instanceof SyntaxError) { - // handle syntax errors + // håndter syntaksfejl } else { - throw err; // unknown error, rethrow it + throw err; // ukendt fejl, kast den videre } } ``` -In the code above we can see two types of errors, but there can be more. +I koden ovenfor kan vi se to typer af fejl, men der kan være flere. -If the `readUser` function generates several kinds of errors, then we should ask ourselves: do we really want to check for all error types one-by-one every time? +Hvis `readUser`-funktionen genererer flere typer af fejl, så bør vi spørge os selv: vil vi virkelig have lyst til at skulle tjekke for alle fejltyper - en efter en - hver gang? -Often the answer is "No": we'd like to be "one level above all that". We just want to know if there was a "data reading error" -- why exactly it happened is often irrelevant (the error message describes it). Or, even better, we'd like to have a way to get the error details, but only if we need to. +Ofte er svaret "Nej": vi vil gerne være "et niveau over alt det". Vi vil bare have at vide om der var en "data læsningsfejl" -- hvorfor det præcist skete er ofte irrelevant (fejlmeddelelsen beskriver det). Eller, endnu bedre, vi vil gerne have en måde at få detaljerne om fejlen på ... men kun hvis vi har brug for dem. -The technique that we describe here is called "wrapping exceptions". +Den teknik vi beskriver her kaldes "wrapping exceptions". -1. We'll make a new class `ReadError` to represent a generic "data reading" error. -2. The function `readUser` will catch data reading errors that occur inside it, such as `ValidationError` and `SyntaxError`, and generate a `ReadError` instead. -3. The `ReadError` object will keep the reference to the original error in its `cause` property. +1. Vi laver en ny klasse `ReadError` til at repræsentere en generisk "data læsning" fejl. +2. Funktionen `readUser` vil fange data læsningsfejl, der opstår inden for den, såsom `ValidationError` og `SyntaxError`, og generere en `ReadError` i stedet. +3. `ReadError`-objektet vil gemme referencen til den originale fejl i sin `cause`-egenskab. -Then the code that calls `readUser` will only have to check for `ReadError`, not for every kind of data reading errors. And if it needs more details of an error, it can check its `cause` property. +Således vil koden, der kalder `readUser`, kun behøve at tjekke for `ReadError`, ikke for hver enkelt type data læsningsfejl. Og hvis den har brug for flere detaljer om en fejl, kan den tjekke dens `cause`-egenskab. -Here's the code that defines `ReadError` and demonstrates its use in `readUser` and `try..catch`: +Her er koden, der definerer `ReadError` og demonstrerer dens brug i `readUser` og `try..catch`: ```js run class ReadError extends Error { @@ -281,7 +281,7 @@ function readUser(json) { } catch (err) { *!* if (err instanceof SyntaxError) { - throw new ReadError("Syntax Error", err); + throw new ReadError("Syntaksfejl", err); } else { throw err; } @@ -293,7 +293,7 @@ function readUser(json) { } catch (err) { *!* if (err instanceof ValidationError) { - throw new ReadError("Validation Error", err); + throw new ReadError("Valideringsfejl", err); } else { throw err; } @@ -317,14 +317,14 @@ try { } ``` -In the code above, `readUser` works exactly as described -- catches syntax and validation errors and throws `ReadError` errors instead (unknown errors are rethrown as usual). +I koden ovenfor fungerer `readUser` præcis som beskrevet -- fanger syntaks- og valideringsfejl og kaster `ReadError`-fejl i stedet (ukendte fejl kastes videre som normalt). -So the outer code checks `instanceof ReadError` and that's it. No need to list all possible error types. +Så den ydre kode tjekker `instanceof ReadError` og det er det. Ingen grund til at gennemgå alle mulige fejltyper. -The approach is called "wrapping exceptions", because we take "low level" exceptions and "wrap" them into `ReadError` that is more abstract. It is widely used in object-oriented programming. +Den kaldes "wrapping exceptions", fordi den tager "low level" undtagelser og "pakker" dem ind i `ReadError` der er mere abstrakt. Denne teknik er meget brugt i objektorienteret programmering. -## Summary +## Opsummering -- We can inherit from `Error` and other built-in error classes normally. We just need to take care of the `name` property and don't forget to call `super`. -- We can use `instanceof` to check for particular errors. It also works with inheritance. But sometimes we have an error object coming from a 3rd-party library and there's no easy way to get its class. Then `name` property can be used for such checks. -- Wrapping exceptions is a widespread technique: a function handles low-level exceptions and creates higher-level errors instead of various low-level ones. Low-level exceptions sometimes become properties of that object like `err.cause` in the examples above, but that's not strictly required. +- Vi kan nedarve fra `Error` og andre indbyggede fejltyper på normal vis. Vi skal bare tage huske på `name`-egenskaben og ikke glemme at kalde `super`. +- Vi kan bruge `instanceof` til at tjekke for bestemte fejl. Det virker også med nedarvning. Men nogle gange har vi et fejlobjekt, der kommer fra en 3.parts bibliotek, hvor der måske ikke er en enkel måde at få dens klasse. Her kan `name`-egenskaben bruges til sådanne tjek. +- Wrapping exceptions er en almindelig teknik: en funktion håndterer lav-niveau undtagelser og opretter højere-niveau fejl i stedet for forskellige lav-niveau fejl. Lav-niveau undtagelser bliver nogle gange til egenskaber på det objekt, som `err.cause` i eksemplerne ovenfor, men det er ikke strengt nødvendigt. diff --git a/1-js/10-error-handling/index.md b/1-js/10-error-handling/index.md index face61c6..aa2db89c 100644 --- a/1-js/10-error-handling/index.md +++ b/1-js/10-error-handling/index.md @@ -1 +1 @@ -# Error handling +# Håndtering af fejl From eeff34d0de0583bded2b41152e1f727fc54fc652 Mon Sep 17 00:00:00 2001 From: ockley Date: Sat, 21 Mar 2026 10:16:47 +0100 Subject: [PATCH 14/21] oversat --- 1-js/11-async/01-callbacks/article.md | 148 +++++++++---------- 1-js/11-async/01-callbacks/callback-hell.svg | 111 +++++++++++++- 2 files changed, 183 insertions(+), 76 deletions(-) diff --git a/1-js/11-async/01-callbacks/article.md b/1-js/11-async/01-callbacks/article.md index 57115a90..754a3e42 100644 --- a/1-js/11-async/01-callbacks/article.md +++ b/1-js/11-async/01-callbacks/article.md @@ -1,68 +1,66 @@ +# Introduktion: callbacks +```warn header="Vi bruger browser metoder i eksemplerne her" +For at demonstrere brugen af callbacks, promises og andre abstrakte koncepter, vil vi bruge nogle browser metoder: specifikt, indlæsning af scripts og udførelse af simple manipulationer af dokumentet. -# Introduction: callbacks +Hvis du ikke er fortrolig med disse metoder, og brugen af dem i eksemplerne er forvirrende, kan du med fordel læse et par kapitler fra den [næste del](/document) af tutorialen. -```warn header="We use browser methods in examples here" -To demonstrate the use of callbacks, promises and other abstract concepts, we'll be using some browser methods: specifically, loading scripts and performing simple document manipulations. - -If you're not familiar with these methods, and their usage in the examples is confusing, you may want to read a few chapters from the [next part](/document) of the tutorial. - -Although, we'll try to make things clear anyway. There won't be anything really complex browser-wise. +Vi vil dog forsøge at gøre tingene så simple og klare som muligt. Der vil ikke være noget virkelig komplekst browser-baseret. ``` -Many functions are provided by JavaScript host environments that allow you to schedule *asynchronous* actions. In other words, actions that we initiate now, but they finish later. +Mange funktioner leveret af JavaScript host miljøer tillader dig at planlægge *asynkrone* handlinger. Med andre ord, handlinger som vi starter nu, men de afsluttes senere. -For instance, one such function is the `setTimeout` function. +For eksempel, en sådan funktion er `setTimeout` funktionen. -There are other real-world examples of asynchronous actions, e.g. loading scripts and modules (we'll cover them in later chapters). +Der er andre eksempler på asynkrone handlinger i den virkelige verden, f.eks. indlæsning af scripts og moduler (vi vil dække dem i senere kapitler). -Take a look at the function `loadScript(src)`, that loads a script with the given `src`: +Tag et kig på funktionen `loadScript(src)`, som loader et script med det givne `src`: ```js function loadScript(src) { - // creates a - - - + } + + function showCircle(cx, cy, radius) { + let div = document.createElement('div'); + div.style.width = 0; + div.style.height = 0; + div.style.left = cx + 'px'; + div.style.top = cy + 'px'; + div.className = 'circle'; + document.body.append(div); + + return new Promise((resolve) => { + setTimeout(() => { + div.style.width = radius * 2 + 'px'; + div.style.height = radius * 2 + 'px'; + + div.addEventListener('transitionend', function handler() { + div.removeEventListener('transitionend', handler); + resolve(div); + }); + }, 0); + }); + } + + diff --git a/1-js/11-async/02-promise-basics/03-animate-circle-promise/task.md b/1-js/11-async/02-promise-basics/03-animate-circle-promise/task.md index 7860a71d..919e3a89 100644 --- a/1-js/11-async/02-promise-basics/03-animate-circle-promise/task.md +++ b/1-js/11-async/02-promise-basics/03-animate-circle-promise/task.md @@ -1,15 +1,15 @@ -# Animated circle with promise +# Animeret cirkel med promise -Rewrite the `showCircle` function in the solution of the task so that it returns a promise instead of accepting a callback. +Omskriv funktionen `showCircle` i løsningen fra opgaven så den returnerer et promise i stedet for at acceptere en callback. -The new usage: +Den nye brug: ```js showCircle(150, 150, 100).then(div => { div.classList.add('message-ball'); - div.append("Hello, world!"); + div.append("Hej, verden!"); }); ``` -Take the solution of the task as the base. +Brug løsningen fra som udgangspunkt. diff --git a/1-js/11-async/02-promise-basics/article.md b/1-js/11-async/02-promise-basics/article.md index 66d9538f..aff25bac 100644 --- a/1-js/11-async/02-promise-basics/article.md +++ b/1-js/11-async/02-promise-basics/article.md @@ -1,92 +1,92 @@ # Promise -Imagine that you're a top singer, and fans ask day and night for your upcoming song. +Forestil dig at du er en kendt sanger og fans spørger dag og nat efter din kommende sang. -To get some relief, you promise to send it to them when it's published. You give your fans a list. They can fill in their email addresses, so that when the song becomes available, all subscribed parties instantly receive it. And even if something goes very wrong, say, a fire in the studio, so that you can't publish the song, they will still be notified. +For at få noget ro til at indspille, lover du at sende den til dem, når den er udgivet. Du giver dine fans en liste. De kan udfylde deres e-mailadresser, så når sangen bliver tilgængelig, modtager alle abonnerede parter den øjeblikkeligt. Og selv hvis noget går meget galt, f.eks. en brand i studiet, så du ikke kan udgive sangen, vil de stadig blive underrettet. -Everyone is happy: you, because the people don't crowd you anymore, and fans, because they won't miss the song. +Alle er glade: du, fordi folk ikke længere presser dig, og dine fans, fordi de ikke kommer til at misse sangen. -This is a real-life analogy for things we often have in programming: +Dette er en analogi fra virkeligheden for en situation vi ofte har i programmering: -1. A "producing code" that does something and takes time. For instance, some code that loads the data over a network. That's a "singer". -2. A "consuming code" that wants the result of the "producing code" once it's ready. Many functions may need that result. These are the "fans". -3. A *promise* is a special JavaScript object that links the "producing code" and the "consuming code" together. In terms of our analogy: this is the "subscription list". The "producing code" takes whatever time it needs to produce the promised result, and the "promise" makes that result available to all of the subscribed code when it's ready. +1. En "producerende kode" der gør noget der tager tid. For eksempel koder der henter data over et netværk - det er "sangeren". +2. En "konsumerende kode" der vil have resultatet af den "producerende kode" når den er klar. Mange funktioner kan have brug for dette resultat - disse er "fans". +3. Et *promise* (på dansk et "løfte") er et specielt JavaScript-objekt, der forbinder "producerende kode" og "konsumerende kode". I vores analogi er dette "abonnementslisten". "Producerende kode" tager den tid det kræver for at producere det lovede resultat, og "promise" gør dette resultat tilgængeligt for alle der har skrevet sig på listen, når den er klar. -The analogy isn't terribly accurate, because JavaScript promises are more complex than a simple subscription list: they have additional features and limitations. But it's fine to begin with. +Analogien er ikke helt nøjagtig, fordi JavaScript-promises er mere komplekse end en simpel abonnementsliste: de har ekstra funktioner og begrænsninger. Men det er fint nok til at begynde med. -The constructor syntax for a promise object is: +Konstruktør-syntaksen for et promise-objekt er: ```js let promise = new Promise(function(resolve, reject) { - // executor (the producing code, "singer") + // udfører (den producerende kode, "sanger") }); ``` -The function passed to `new Promise` is called the *executor*. When `new Promise` is created, the executor runs automatically. It contains the producing code which should eventually produce the result. In terms of the analogy above: the executor is the "singer". +Den funktion der gives til `new Promise` kaldes *executor* (i stil med udfører på dansk). Når `new Promise` er oprettet, køres executor'en automatisk. Den indeholder den producerende kode, som bør producere resultatet i sidste ende. I termer af vores analogi: executor'en er "sangeren". -Its arguments `resolve` and `reject` are callbacks provided by JavaScript itself. Our code is only inside the executor. +Dens argumenter `resolve` og `reject` er callbacks leveret af JavaScript selv. Vores kode er kun inde i executor'en. -When the executor obtains the result, be it soon or late, doesn't matter, it should call one of these callbacks: +Når executor'en får resultatet, uanset hvor hurtigt eller langsomt, spiller det ingen rolle, så bør den kalde en af disse callbacks: -- `resolve(value)` — if the job is finished successfully, with result `value`. -- `reject(error)` — if an error has occurred, `error` is the error object. +- `resolve(value)` — hvis jobbet er færdigt med succes, med resultat `value`. +- `reject(error)` — hvis der er opstået en fejl, `error` er fejl-objektet. -So to summarize: the executor runs automatically and attempts to perform a job. When it is finished with the attempt, it calls `resolve` if it was successful or `reject` if there was an error. +Så for at opsummere: Executor'en kører automatisk og forsøger at udføre et job. Når det er færdigt med forsøget, kalder den `resolve` hvis det lykkedes eller `reject` hvis der var en fejl. -The `promise` object returned by the `new Promise` constructor has these internal properties: +Objektet `promise` som returneres af `new Promise` constructor har disse interne egenskaber: -- `state` — initially `"pending"`, then changes to either `"fulfilled"` when `resolve` is called or `"rejected"` when `reject` is called. -- `result` — initially `undefined`, then changes to `value` when `resolve(value)` is called or `error` when `reject(error)` is called. +- `state` — starter med at være `"pending"`, men ændres til enten `"fulfilled"` når `resolve` kaldes eller `"rejected"` når `reject` kaldes. +- `result` — starter med at være `undefined`, men ændres til `value` når `resolve(value)` kaldes eller `error` når `reject(error)` kaldes. -So the executor eventually moves `promise` to one of these states: +Så executor'en bevæger `promise` til en af disse tilstande: ![](promise-resolve-reject.svg) -Later we'll see how "fans" can subscribe to these changes. +Senere vil vi se, hvordan "fans" kan abonnere på disse ændringer. -Here's an example of a promise constructor and a simple executor function with "producing code" that takes time (via `setTimeout`): +Her er et eksempel på en promise konstruktør og en simpel executor-funktion med "producerende kode" der tager tid (via `setTimeout`): ```js let promise = new Promise(function(resolve, reject) { - // the function is executed automatically when the promise is constructed + // funktionen udføres automatisk når promise'et er konstrueret - // after 1 second signal that the job is done with the result "done" + // efter 1 sekund signalerer at jobbet er færdigt med resultatet "done" setTimeout(() => *!*resolve("done")*/!*, 1000); }); ``` -We can see two things by running the code above: +Vi kan se to ting ved at køre koden ovenfor: -1. The executor is called automatically and immediately (by `new Promise`). -2. The executor receives two arguments: `resolve` and `reject`. These functions are pre-defined by the JavaScript engine, so we don't need to create them. We should only call one of them when ready. +1. Executor'en kaldes automatisk og umiddelbart (af `new Promise`). +2. Executor'en modtager to argumenter: `resolve` og `reject`. Disse funktioner er foruddefinerede af JavaScript-motoren, så vi behøver ikke at oprette dem. Vi bør kun kalde en af dem når vi er klar. - After one second of "processing", the executor calls `resolve("done")` to produce the result. This changes the state of the `promise` object: + Efter et sekund af "behandling", kalder executor'en `resolve("done")` for at producere resultatet. Dette ændrer tilstanden på `promise`-objektet til `"fulfilled"` og sætter `result` til `"done"`: ![](promise-resolve-1.svg) -That was an example of a successful job completion, a "fulfilled promise". +Det var et eksempel på et succesfuldt job, et "fuldført løfte". -And now an example of the executor rejecting the promise with an error: +Og nu et eksempel på executor'en afviser løftet med en fejl: ```js let promise = new Promise(function(resolve, reject) { - // after 1 second signal that the job is finished with an error + // efter 1 sekund signalerer at jobbet er færdigt med en fejl setTimeout(() => *!*reject(new Error("Whoops!"))*/!*, 1000); }); ``` -The call to `reject(...)` moves the promise object to `"rejected"` state: +Kaldet til `reject(...)` flytter promise objektet til `"rejected"` state: ![](promise-reject-1.svg) -To summarize, the executor should perform a job (usually something that takes time) and then call `resolve` or `reject` to change the state of the corresponding promise object. +For at opsummere, executor udfører et job (ofte noget der tager tid) og kalder så `resolve` eller `reject` for at ændre tilstanden på det tilsvarende promise-objekt. -A promise that is either resolved or rejected is called "settled", as opposed to an initially "pending" promise. +Et løfte der enten opfyldes eller afvises kaldes for "settled", modsat den oprindelige tilstand "pending". -````smart header="There can be only a single result or an error" -The executor should call only one `resolve` or one `reject`. Any state change is final. +````smart header="Der kan der kun være et enkelt resultat eller en fejl" +Executor'en bør kun kalde en enkelt `resolve` eller en enkelt `reject`. Enhver ændring af state er endelig. -All further calls of `resolve` and `reject` are ignored: +Alle efterfølgende kald af `resolve` og `reject` ignoreres: ```js let promise = new Promise(function(resolve, reject) { @@ -94,95 +94,95 @@ let promise = new Promise(function(resolve, reject) { resolve("done"); */!* - reject(new Error("…")); // ignored - setTimeout(() => resolve("…")); // ignored + reject(new Error("…")); // ignoreret + setTimeout(() => resolve("…")); // ignoreret }); ``` -The idea is that a job done by the executor may have only one result or an error. +Idéen er at når et job er færdigt, kan det kun have ét resultat eller en fejl. -Also, `resolve`/`reject` expect only one argument (or none) and will ignore additional arguments. +Derudover arbejder `resolve`/`reject` med kun ét argument (eller intet) og vil ignorere yderligere argumenter. ```` -```smart header="Reject with `Error` objects" -In case something goes wrong, the executor should call `reject`. That can be done with any type of argument (just like `resolve`). But it is recommended to use `Error` objects (or objects that inherit from `Error`). The reasoning for that will soon become apparent. +```smart header="Afvis med `Error` objekter" +I det tilfælde at noget går galt, bør executor'en kalde `reject`. Det kan gøres med enhver type af argument (ligesom `resolve`). Men det er anbefalet at bruge `Error` objekter (eller objekter der nedarver fra `Error`). Årsagen til det vil snart blive klart. ``` -````smart header="Immediately calling `resolve`/`reject`" -In practice, an executor usually does something asynchronously and calls `resolve`/`reject` after some time, but it doesn't have to. We also can call `resolve` or `reject` immediately, like this: +````smart header="Umiddelbart kald af `resolve`/`reject`" +I praksis udfører en executor en job asynkront og kalder `resolve`/`reject` efter noget tid, men det behøver ikke at være tilfældet. Vi kan også kalde `resolve` eller `reject` umiddelbart, som her: ```js let promise = new Promise(function(resolve, reject) { - // not taking our time to do the job - resolve(123); // immediately give the result: 123 + // det tager ikke nogen tid at gøre jobbet + resolve(123); // giv resultatet med det samme: 123 }); ``` -For instance, this might happen when we start to do a job but then see that everything has already been completed and cached. +Det kan ske, hvis vi starter et job, men derefter ser, at alt allerede er fuldført og cached. -That's fine. We immediately have a resolved promise. +Det er helt fint. Så har vi bare umiddelbart et resolved promise. ```` -```smart header="The `state` and `result` are internal" -The properties `state` and `result` of the Promise object are internal. We can't directly access them. We can use the methods `.then`/`.catch`/`.finally` for that. They are described below. +```smart header="`state` og `result` er interne" +Egenskaberne `state` og `result` fra Promise objektet er interne. Vi kan ikke tilgå dem direkte. Vi kan bruge metoderne `.then`/`.catch`/`.finally` til det. De er beskrevet nedenfor. ``` -## Consumers: then, catch +## Forbrugerne: then, catch -A Promise object serves as a link between the executor (the "producing code" or "singer") and the consuming functions (the "fans"), which will receive the result or error. Consuming functions can be registered (subscribed) using the methods `.then` and `.catch`. +Et Promise objekt fungerer som en link mellem executor (den "producerende kode" eller "sanger") og de forbrugerfunktioner (de "fans"), som vil modtage resultatet eller fejlen. Forbrugerfunktioner kan registrere sig (abonnere) ved hjælp af metoderne `.then` og `.catch`. ### then -The most important, fundamental one is `.then`. +Det vigtigste (og fundamentale) er `.then`. -The syntax is: +Syntaksen er: ```js promise.then( - function(result) { *!*/* handle a successful result */*/!* }, - function(error) { *!*/* handle an error */*/!* } + function(result) { *!*/* håndter et succesfuldt resultat */*/!* }, + function(error) { *!*/* håndter en fejl */*/!* } ); ``` -The first argument of `.then` is a function that runs when the promise is resolved and receives the result. +Det første argument af `.then` er en funktion der kører når løftet opfyldes og vi modtager et resultat. -The second argument of `.then` is a function that runs when the promise is rejected and receives the error. +Det andet argument af `.then` er en funktion der kører når løftet afvises og vi modtager en fejl. -For instance, here's a reaction to a successfully resolved promise: +Her er et eksempel på en reaktion til et succesfuldt løft: ```js run let promise = new Promise(function(resolve, reject) { setTimeout(() => resolve("done!"), 1000); }); -// resolve runs the first function in .then +// resolve kører den første funktion i .then promise.then( *!* - result => alert(result), // shows "done!" after 1 second + result => alert(result), // viser "done!" efter 1 sekund */!* - error => alert(error) // doesn't run + error => alert(error) // kører ikke ); ``` -The first function was executed. +Den første funktion blev eksekveret. -And in the case of a rejection, the second one: +Og i tilfælde af en afvisning, den anden funktion: ```js run let promise = new Promise(function(resolve, reject) { - setTimeout(() => reject(new Error("Whoops!")), 1000); + setTimeout(() => reject(new Error("Ups!")), 1000); }); -// reject runs the second function in .then +// reject kører den anden funktion i .then promise.then( - result => alert(result), // doesn't run + result => alert(result), // kører ikke *!* - error => alert(error) // shows "Error: Whoops!" after 1 second + error => alert(error) // viser "Error: Ups!" efter 1 sekund */!* ); ``` -If we're interested only in successful completions, then we can provide only one function argument to `.then`: +Hvis vi kun er interesseret i succesfulde afslutninger, så kan vi nøjes med kun at give et argument til `.then`: ```js run let promise = new Promise(resolve => { @@ -190,125 +190,125 @@ let promise = new Promise(resolve => { }); *!* -promise.then(alert); // shows "done!" after 1 second +promise.then(alert); // viser "done!" efter 1 sekund */!* ``` ### catch -If we're interested only in errors, then we can use `null` as the first argument: `.then(null, errorHandlingFunction)`. Or we can use `.catch(errorHandlingFunction)`, which is exactly the same: +Hvis vi kun er interesseret i fejl, så kan vi bruge `null` som det første argument: `.then(null, errorHandlingFunction)`. Eller vi kan bruge `.catch(errorHandlingFunction)`, som er præcis det samme: ```js run let promise = new Promise((resolve, reject) => { - setTimeout(() => reject(new Error("Whoops!")), 1000); + setTimeout(() => reject(new Error("Ups!")), 1000); }); *!* // .catch(f) is the same as promise.then(null, f) -promise.catch(alert); // shows "Error: Whoops!" after 1 second +promise.catch(alert); // viser "Error: Ups!" efter 1 sekund */!* ``` -The call `.catch(f)` is a complete analog of `.then(null, f)`, it's just a shorthand. +Klausulen `.catch(f)` er fuldstændig det samme som `.then(null, f)`. -## Cleanup: finally +## Oprydning: finally -Just like there's a `finally` clause in a regular `try {...} catch {...}`, there's `finally` in promises. +Ligesom der er en `finally` klausul i en `try {...} catch {...}`, er der også en `finally` i promises. -The call `.finally(f)` is similar to `.then(f, f)` in the sense that `f` runs always, when the promise is settled: be it resolve or reject. +Kaldet til `.finally(f)` minder om `.then(f, f)` i den forstand at `f` altid kører, når promise er blevet afsluttet: enten resolve eller reject. -The idea of `finally` is to set up a handler for performing cleanup/finalizing after the previous operations are complete. +Idéen med `finally` er at opstille håndtering der rydder op eller færdiggører processen efter de tidligere operationer er fuldført. -E.g. stopping loading indicators, closing no longer needed connections, etc. +Det kan være ting som at stoppe loading indicators, lukke forbindelser der ikke længere er nødvendige, etc. -Think of it as a party finisher. Irresepective of whether a party was good or bad, how many friends were in it, we still need (or at least should) do a cleanup after it. +Tænk på det som en oprydder efter festen. Det er ligegyldigt om festen var god eller dårlig, hvor mange venner der var med oev. Vi skal stadig (eller i det mindste bør vi stadig) rydde op efter den. -The code may look like this: +Koden kan se sådan ud: ```js new Promise((resolve, reject) => { - /* do something that takes time, and then call resolve or maybe reject */ + /* gør noget der tager tid, og kald derefter resolve eller reject */ }) *!* - // runs when the promise is settled, doesn't matter successfully or not + // køres når promise er blevet afsluttet, det spiller ingen rolle om det lykkes eller ej .finally(() => stop loading indicator) - // so the loading indicator is always stopped before we go on + // Kode der gør at loading indikatoren er altid stoppet før vi går videre */!* .then(result => show result, err => show error) ``` -Please note that `finally(f)` isn't exactly an alias of `then(f,f)` though. +Bemærk at `finally(f)` ikke helt er det samme som `then(f,f)`. -There are important differences: +Der er nogle vigtig forskelle: -1. A `finally` handler has no arguments. In `finally` we don't know whether the promise is successful or not. That's all right, as our task is usually to perform "general" finalizing procedures. +1. En `finally` handler har ingen argumenter. I `finally` ved vi ikke om løftet er opfyldt eller ej. Det er ok, da vores opgave her ofter er at udføre "generelle" opgaver for at afslutte processen. - Please take a look at the example above: as you can see, the `finally` handler has no arguments, and the promise outcome is handled by the next handler. -2. A `finally` handler "passes through" the result or error to the next suitable handler. + Tag et kig på eksemplet ovenfor: som du kan se, har `finally` handler ingen argumenter, og promise udfaldet håndteres af den næste handler. +2. En `finally` handler "sender information igennem" til den næste egnede handler - hvad end det er et result eller error. - For instance, here the result is passed through `finally` to `then`: + Her sendes resultatet for eksempel gennem `finally` til `then`: ```js run new Promise((resolve, reject) => { setTimeout(() => resolve("value"), 2000); }) - .finally(() => alert("Promise ready")) // triggers first - .then(result => alert(result)); // <-- .then shows "value" + .finally(() => alert("Promise klart")) // trigger først + .then(result => alert(result)); // <-- .then viser "value" ``` - As you can see, the `value` returned by the first promise is passed through `finally` to the next `then`. + Som du kan se sendes værdien `value` der returneres fra det første promise til `finally` og gennem den videre til den næste `then`. - That's very convenient, because `finally` is not meant to process a promise result. As said, it's a place to do generic cleanup, no matter what the outcome was. + Det er meget praktisk fordi `finally` er ikke sat i verden for at behandling resultatet af dit promise. Som sagt, er det et sted til generel oprydning, uanset hvad udfaldet var. - And here's an example of an error, for us to see how it's passed through `finally` to `catch`: + He rer et eksempel med en fejl, for os at vise hvordan den bliver sendt gennem `finally` til `catch`: ```js run new Promise((resolve, reject) => { throw new Error("error"); }) - .finally(() => alert("Promise ready")) // triggers first - .catch(err => alert(err)); // <-- .catch shows the error + .finally(() => alert("Promise klart")) // trigger først + .catch(err => alert(err)); // <-- .catch viser fejlen ``` -3. A `finally` handler also shouldn't return anything. If it does, the returned value is silently ignored. +3. En `finally` handler skal heller ikke returnere noget. Hvis den gør, ignoreres den returnerede værdi stille. - The only exception to this rule is when a `finally` handler throws an error. Then this error goes to the next handler, instead of any previous outcome. + Den eneste undtagelse til den regel er, når en `finally` handler smider en fejl. Så er det denne fejl der bliver sendt til den næste handler, istedet for et tidligere resultat. -To summarize: +For at opsummere: -- A `finally` handler doesn't get the outcome of the previous handler (it has no arguments). This outcome is passed through instead, to the next suitable handler. -- If a `finally` handler returns something, it's ignored. -- When `finally` throws an error, then the execution goes to the nearest error handler. +- En `finally` handler får ikke det resultat fra den forrige handler (den har ingen argumenter). Dette resultat bliver i stedet sendt videre til den næste egnede handler. +- Hvis en `finally` handler returnerer noget, ignoreres det. +- Når `finally` kaster en fejl, går udførelsen til den nærmeste fejlhandler. -These features are helpful and make things work just the right way if we use `finally` how it's supposed to be used: for generic cleanup procedures. +Disse funktioner er hjælpsome og gør at tingene fungerer på den rigtige måde, hvis vi bruger `finally` som det er ment: til generelle oprydningsprocedurer. -````smart header="We can attach handlers to settled promises" -If a promise is pending, `.then/catch/finally` handlers wait for its outcome. +````smart header="Vi kan tilføje handlers til afsluttede promises" +Hvis et promise står som pending, `.then/catch/finally` vil handlers vente på dets resultat. -Sometimes, it might be that a promise is already settled when we add a handler to it. +Der kan være tilfælde, vore et løfte allerede er afsluttet, når handleren bliver tilføjet. -In such case, these handlers just run immediately: +I sådanne tilfælde vil disse handlers bare køre med det samme: ```js run -// the promise becomes resolved immediately upon creation +// Denne promise bliver sat til resolved med det samme den oprettes let promise = new Promise(resolve => resolve("done!")); -promise.then(alert); // done! (shows up right now) +promise.then(alert); // done! (Vises med det samme) ``` -Note that this makes promises more powerful than the real life "subscription list" scenario. If the singer has already released their song and then a person signs up on the subscription list, they probably won't receive that song. Subscriptions in real life must be done prior to the event. +Bemærk at dette gør promises mere kraftfulde end scenariet med "subscription list" i det virkelige liv. Hvis en sanger forsynlig har frigivet deres sang og en person tilmelder sig på abonnementslisten efterfølgende, vil de sandsynligvis ikke modtage den sang der allerede er udkommet. Abonnementer i det virkelige liv skal foretages før begivenheden for at virke. -Promises are more flexible. We can add handlers any time: if the result is already there, they just execute. +Promises er mere fleksible. Vi kan tilføje handlers når som helst: hvis resultatet allerede er der, så udføres de bare. ```` -## Example: loadScript [#loadscript] +## Eksempel: loadScript [#loadscript] -Next, let's see more practical examples of how promises can help us write asynchronous code. +Lad os nu se et par praktiske eksempler på hvordan promises kan hjælpe os med at skrive asynkron kode. -We've got the `loadScript` function for loading a script from the previous chapter. +Vi har `loadScript` funktionen der henter et script fra det forrige kapitel. -Here's the callback-based variant, just to remind us of it: +Her er den callback-baserede variant, for lige at genopfriske hukommelsen: ```js function loadScript(src, callback) { @@ -322,9 +322,9 @@ function loadScript(src, callback) { } ``` -Let's rewrite it using Promises. +Lad os omskrive den til at gøre brug af Promises. -The new function `loadScript` will not require a callback. Instead, it will create and return a Promise object that resolves when the loading is complete. The outer code can add handlers (subscribing functions) to it using `.then`: +Den nye funktion `loadScript` kræver ikke en callback. I stedet vil den oprette og returnere et Promise-objekt, der løser sig, når indlæsningen er fuldført. Den ydre kode kan tilføje handlers (abonnentfunktioner) til det ved hjælp af `.then`: ```js run function loadScript(src) { @@ -340,25 +340,25 @@ function loadScript(src) { } ``` -Usage: +Den bruges således: ```js run let promise = loadScript("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"); promise.then( - script => alert(`${script.src} is loaded!`), - error => alert(`Error: ${error.message}`) + script => alert(`${script.src} er hentet!`), + error => alert(`Fejl: ${error.message}`) ); -promise.then(script => alert('Another handler...')); +promise.then(script => alert('Endnu en handler...')); ``` -We can immediately see a few benefits over the callback-based pattern: +Vi kan med det samme se et par fordele i forhold til det callback-baserede mønster: | Promises | Callbacks | |----------|-----------| -| Promises allow us to do things in the natural order. First, we run `loadScript(script)`, and `.then` we write what to do with the result. | We must have a `callback` function at our disposal when calling `loadScript(script, callback)`. In other words, we must know what to do with the result *before* `loadScript` is called. | -| We can call `.then` on a Promise as many times as we want. Each time, we're adding a new "fan", a new subscribing function, to the "subscription list". More about this in the next chapter: [](info:promise-chaining). | There can be only one callback. | +| Promises tillader os at gøre tingene i den naturlige rækkefølge. Først kører vi `loadScript(script)`, og `.then` skriver vi, hvad vi vil gøre med resultatet. | Vi skal have en `callback`-funktion til rådighed, når vi kalder `loadScript(script, callback)`. Med andre ord skal vi vide, hvad vi vil gøre med resultatet *før* `loadScript` kaldes. | +| Vi kan kalde `.then` på et Promise så mange gange som vi vil. Hver gang tilføjer vi en ny "fan", en ny abonnentfunktion, til "abonnementslisten". Mere om dette i næste kapitel: [](info:promise-chaining). | Der kan kun være én callback. | -So promises give us better code flow and flexibility. But there's more. We'll see that in the next chapters. +Så promises giver os bedre kodeflow og fleksibilitet. Men der er mere. Det vil vi se nærmere på i næste kapitler. From 3e9f9badd9491fad11b510a918ec5f8bf1e59977 Mon Sep 17 00:00:00 2001 From: ockley Date: Mon, 23 Mar 2026 15:20:57 +0100 Subject: [PATCH 16/21] Oversat til dansk --- .../01-then-vs-catch/solution.md | 10 +- .../01-then-vs-catch/task.md | 2 +- 1-js/11-async/03-promise-chaining/article.md | 167 +++++++++--------- .../03-promise-chaining/getMessage.js | 2 +- .../promise-handler-variants.svg | 117 +++++++++++- 5 files changed, 206 insertions(+), 92 deletions(-) diff --git a/1-js/11-async/03-promise-chaining/01-then-vs-catch/solution.md b/1-js/11-async/03-promise-chaining/01-then-vs-catch/solution.md index bdd1c643..060a2cdc 100644 --- a/1-js/11-async/03-promise-chaining/01-then-vs-catch/solution.md +++ b/1-js/11-async/03-promise-chaining/01-then-vs-catch/solution.md @@ -1,6 +1,6 @@ -The short answer is: **no, they are not equal**: +Det korte svar er: **nej, de er ikke ens**: -The difference is that if an error happens in `f1`, then it is handled by `.catch` here: +Forskellen er, at hvis en fejl opstår i `f1`, så håndteres den af `.catch` her: ```js run promise @@ -8,13 +8,13 @@ promise .catch(f2); ``` -...But not here: +... men ikke her: ```js run promise .then(f1, f2); ``` -That's because an error is passed down the chain, and in the second code piece there's no chain below `f1`. +Det er fordi at fejl bliver sendt ned gennem kæden, og i det andet kodeeksempel er der ingen kæde under `f1`. -In other words, `.then` passes results/errors to the next `.then/catch`. So in the first example, there's a `catch` below, and in the second one there isn't, so the error is unhandled. +Med andre ord, `.then` sender resultater/fejl videre til den næste `.then/catch`. Så i det første eksempel er der en `catch` nedenfor, og i det andet er der ikke, så fejlen håndteres ikke. diff --git a/1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md b/1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md index cefca60a..b3ca4ba4 100644 --- a/1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md +++ b/1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md @@ -1,6 +1,6 @@ # Promise: then versus catch -Are these code fragments equal? In other words, do they behave the same way in any circumstances, for any handler functions? +Er disse to fragmenter af kode ens? Med andre ord, gør de det samme i enhver sammenhæng, for enhver handler funktion? ```js promise.then(f1).catch(f2); diff --git a/1-js/11-async/03-promise-chaining/article.md b/1-js/11-async/03-promise-chaining/article.md index a33ca258..281b668b 100644 --- a/1-js/11-async/03-promise-chaining/article.md +++ b/1-js/11-async/03-promise-chaining/article.md @@ -1,13 +1,13 @@ -# Promises chaining +# Sammenkædning af promises (chaining) -Let's return to the problem mentioned in the chapter : we have a sequence of asynchronous tasks to be performed one after another — for instance, loading scripts. How can we code it well? +Lad os vende tilbage til problemet nævnt i kapitlet : vi har en sekvens af asynkrone opgaver, der skal udføres efter hinanden — for eksempel, indlæsning af scripts. Hvordan kan vi kode det godt? -Promises provide a couple of recipes to do that. +Promises leverer et par metoder til at gøre det. -In this chapter we cover promise chaining. +I dette kapitel dækker vi promise chaining. -It looks like this: +Det ser ud som dette: ```js run new Promise(function(resolve, reject) { @@ -32,23 +32,23 @@ new Promise(function(resolve, reject) { }); ``` -The idea is that the result is passed through the chain of `.then` handlers. +Idéen her er, at resultatet sendes gennem en kæde af `.then`-håndteringer. -Here the flow is: -1. The initial promise resolves in 1 second `(*)`, -2. Then the `.then` handler is called `(**)`, which in turn creates a new promise (resolved with `2` value). -3. The next `then` `(***)` gets the result of the previous one, processes it (doubles) and passes it to the next handler. -4. ...and so on. +Her er flowet: +1. Det indledende promise løser sig efter 1 sekund `(*)`, +2. Derefter kaldes `.then` handleren `(**)`, der derefter opretter et nyt promise (løst med værdien `2`). +3. Det næste `then` `(***)` får resultatet fra den forrige, behandler det (dobbelt) og sender det videre til den næste handler. +4. ...og sådan videre. -As the result is passed along the chain of handlers, we can see a sequence of `alert` calls: `1` -> `2` -> `4`. +Efterhånden som resultatet sendes gennem kæden af håndteringer, kan vi se en sekvens af `alert`-kald: `1` -> `2` -> `4`. ![](promise-then-chain.svg) -The whole thing works, because every call to a `.then` returns a new promise, so that we can call the next `.then` on it. +Dette virker, fordi hvert kald til en `.then` returnerer et nyt promise, så vi kan kalde næste `.then` på det. -When a handler returns a value, it becomes the result of that promise, so the next `.then` is called with it. +Når en handler returnerer en værdi, bliver den til resultatet af det promise, så næste `.then` kaldes med den. -**A classic newbie error: technically we can also add many `.then` to a single promise. This is not chaining.** +**En klassisk begynderfejl: teknisk set kan vi også tilføje mange `.then` til et enkelt promise. Dette er ikke chaining.** For example: ```js run @@ -72,23 +72,23 @@ promise.then(function(result) { }); ``` -What we did here is just adding several handlers to one promise. They don't pass the result to each other; instead they process it independently. +Det vi har gjort her er blot at tilføje flere håndteringer til et enkelt promise. De sender ikke resultatet videre til hinanden; de behandler det uafhængigt. -Here's the picture (compare it with the chaining above): +Her er et billede (til sammenligning med kæden ovenfor): ![](promise-then-many.svg) -All `.then` on the same promise get the same result -- the result of that promise. So in the code above all `alert` show the same: `1`. +Alle `.then` der direkte er tilknyttet det samme promise får det samme resultat -- resultatet af det promise. Så i koden ovenfor viser alle `alert` den samme værdi: `1`. -In practice we rarely need multiple handlers for one promise. Chaining is used much more often. +I praksis har vi sjældent brug for flere håndteringer for et enkelt promise. Kæden bruges meget mere ofte. -## Returning promises +## Returnering af promises -A handler, used in `.then(handler)` may create and return a promise. +En handler brugt i `.then(handler)` må oprette og returnere et promise. -In that case further handlers wait until it settles, and then get its result. +I det tilfælde venter næste håndteringer på, at det promise bliver løst, og derefter får de dets resultat. -For instance: +For eksempel: ```js run new Promise(function(resolve, reject) { @@ -120,15 +120,15 @@ new Promise(function(resolve, reject) { }); ``` -Here the first `.then` shows `1` and returns `new Promise(…)` in the line `(*)`. After one second it resolves, and the result (the argument of `resolve`, here it's `result * 2`) is passed on to the handler of the second `.then`. That handler is in the line `(**)`, it shows `2` and does the same thing. +Her viser den første `.then` `1` og returnerer `new Promise(…)` i linjen `(*)`. Efter et sekund løser den sig, og resultatet (argumentet for `resolve`, her er det `result * 2`) sendes videre til håndtereren for den anden `.then`. Den håndterer er i linjen `(**)`, den viser `2` og gør det samme. -So the output is the same as in the previous example: 1 -> 2 -> 4, but now with 1 second delay between `alert` calls. +Så outputtet er det samme som i det forrige eksempel: 1 -> 2 -> 4, men nu med 1 sekund forsinkelse mellem `alert`-kald. -Returning promises allows us to build chains of asynchronous actions. +Returnering af promises tillader os at bygge kæder af asynchronous handlinger. -## Example: loadScript +## Eksempel: loadScript -Let's use this feature with the promisified `loadScript`, defined in the [previous chapter](info:promise-basics#loadscript), to load scripts one by one, in sequence: +Lad os bruge den mulighed i vores "promisificerede" `loadScript`, som vi oprettede i [sidste kapitel](info:promise-basics#loadscript), til at hente scripts et ad gangen, i sekvens: ```js run loadScript("/article/promise-chaining/one.js") @@ -139,22 +139,22 @@ loadScript("/article/promise-chaining/one.js") return loadScript("/article/promise-chaining/three.js"); }) .then(function(script) { - // use functions declared in scripts - // to show that they indeed loaded + // udfør funktionerne deklareret i de hentede scripts + // for at vise, at de rent faktisk er hentet one(); two(); three(); }); ``` -This code can be made bit shorter with arrow functions: +Denne kode kan gøres lidt kortere med arrow funktioner: ```js run loadScript("/article/promise-chaining/one.js") .then(script => loadScript("/article/promise-chaining/two.js")) .then(script => loadScript("/article/promise-chaining/three.js")) .then(script => { - // scripts are loaded, we can use functions declared there + // scripts er alle hentet. Nu kan vi bruge funktionerne one(); two(); three(); @@ -162,17 +162,17 @@ loadScript("/article/promise-chaining/one.js") ``` -Here each `loadScript` call returns a promise, and the next `.then` runs when it resolves. Then it initiates the loading of the next script. So scripts are loaded one after another. +Her returnerer hvert kald til `loadScript` et promise og den næste `.then` kører, når det løses (resolve). Derefter initialiseres hentning af det næste script. Så scripts er hentet en efter en. -We can add more asynchronous actions to the chain. Please note that the code is still "flat" — it grows down, not to the right. There are no signs of the "pyramid of doom". +Vi kan tilføje endnu flere asynkrone handlinger til kæden. Bemærk, at koden stadig er "flad" — den vokser ned, ikke til højre. Der er ingen tegn på "pyramid of doom". -Technically, we could add `.then` directly to each `loadScript`, like this: +Teknisk set kunne vi tilføje `.then` direkte til hvert `loadScript`, som dette: ```js run loadScript("/article/promise-chaining/one.js").then(script1 => { loadScript("/article/promise-chaining/two.js").then(script2 => { loadScript("/article/promise-chaining/three.js").then(script3 => { - // this function has access to variables script1, script2 and script3 + // denne funktion har adgang til variablene script1, script2 and script3 one(); two(); three(); @@ -181,19 +181,19 @@ loadScript("/article/promise-chaining/one.js").then(script1 => { }); ``` -This code does the same: loads 3 scripts in sequence. But it "grows to the right". So we have the same problem as with callbacks. +Denne kode gør det samme: henter 3 scripts i sekvens. Men den "vokser til højre". Så vi har det samme problem som med callbacks. -People who start to use promises sometimes don't know about chaining, so they write it this way. Generally, chaining is preferred. +Folk der starter med at bruge promises ved ikke altid om chaining, så de skriver det på denne måde. Generelt set er chaining at foretrække. -Sometimes it's ok to write `.then` directly, because the nested function has access to the outer scope. In the example above the most nested callback has access to all variables `script1`, `script2`, `script3`. But that's an exception rather than a rule. +Nogle gange er det i orden at skrive `.then` direkte, fordi den indlejrede funktion har adgang til det ydre scope. I eksemplet ovenfor har den mest indlejrede callback adgang til alle variabler `script1`, `script2`, `script3`. Men det er mere en undtagelse end en regel. ````smart header="Thenables" -To be precise, a handler may return not exactly a promise, but a so-called "thenable" object - an arbitrary object that has a method `.then`. It will be treated the same way as a promise. +For at være præcis, kan en handler returnerer ikke nødvendigvis et promise, men et såkaldt "thenable" objekt - et vilkårligt objekt som har en metode `.then`. Det vil blive behandlet på samme måde som en promise. -The idea is that 3rd-party libraries may implement "promise-compatible" objects of their own. They can have an extended set of methods, but also be compatible with native promises, because they implement `.then`. +Ideen er, at 3rd-party biblioteker kan implementere deres egne "promise-kompatible" objekter. De kan have et udvidet sæt af metoder, men også være kompatible med native promises, fordi de implementerer `.then`. -Here's an example of a thenable object: +Her er et eksempel på et thenable objekt: ```js run class Thenable { @@ -201,8 +201,8 @@ class Thenable { this.num = num; } then(resolve, reject) { - alert(resolve); // function() { native code } - // resolve with this.num*2 after the 1 second + alert(resolve); // function() { native kode } + // resolve med this.num*2 efter 1 sekund setTimeout(() => resolve(this.num * 2), 1000); // (**) } } @@ -213,70 +213,69 @@ new Promise(resolve => resolve(1)) return new Thenable(result); // (*) */!* }) - .then(alert); // shows 2 after 1000ms + .then(alert); // vis 2 efter 1000ms ``` -JavaScript checks the object returned by the `.then` handler in line `(*)`: if it has a callable method named `then`, then it calls that method providing native functions `resolve`, `reject` as arguments (similar to an executor) and waits until one of them is called. In the example above `resolve(2)` is called after 1 second `(**)`. Then the result is passed further down the chain. - -This feature allows us to integrate custom objects with promise chains without having to inherit from `Promise`. -```` +JavaScript tjekker objektet der returneres af `.then` handleren i linje `(*)`: Hvis den har en kaldbar metode kaldet `then`, så kalder den den metode og giver native funktioner `resolve`, `reject` som argumenter (ligner en executor) og venter indtil en af dem bliver kaldt. I eksemplet ovenfor bliver `resolve(2)` kaldt efter 1 sekund `(**)`. Derefter sendes resultatet videre ned ad kæden. +Denne feature tillader os at integrere custom objekter med promise kæder uden at skulle arve fra `Promise`. +``` -## Bigger example: fetch +## Et større eksempel: fetch -In frontend programming, promises are often used for network requests. So let's see an extended example of that. +I frontend programmering bruges promises ofte til forespørgsler over netværket. Så lad os se på et eksempel på det. -We'll use the [fetch](info:fetch) method to load the information about the user from the remote server. It has a lot of optional parameters covered in [separate chapters](info:fetch), but the basic syntax is quite simple: +Vi vil bruge metoden [fetch](info:fetch) til at indlæse informationen om brugeren fra den eksterne server. Den har en masse valgfrie parametre dækket i [separate kapitler](info:fetch), men den grundlæggende syntaks er ganske enkel: ```js let promise = fetch(url); ``` -This makes a network request to the `url` and returns a promise. The promise resolves with a `response` object when the remote server responds with headers, but *before the full response is downloaded*. +Dette opretter en netværksforespørgsel til `url` og returnerer en promise. Promise'en løser med et `response`-objekt, når den eksterne server svarer med headers, men *før hele svaret er downloadet*. -To read the full response, we should call the method `response.text()`: it returns a promise that resolves when the full text is downloaded from the remote server, with that text as a result. +For at læse hele svaret, bør vi kalde metoden `response.text()`: den returnerer en promise, der løser, når hele teksten er downloadet fra den eksterne server, med den tekst som resultat. -The code below makes a request to `user.json` and loads its text from the server: +Koden nedenfor laver en forespørgsel til `user.json` og indlæser dens tekst fra serveren: ```js run fetch('/article/promise-chaining/user.json') - // .then below runs when the remote server responds + // .then nedenfor kører når remote serveren svarer .then(function(response) { - // response.text() returns a new promise that resolves with the full response text - // when it loads + // response.text() returnerer et nyt promise der løses med den fulde tekst af det eksterne fil, + // når den er indlæst return response.text(); }) .then(function(text) { - // ...and here's the content of the remote file + // ... og her er indholdet af det eksterne fil alert(text); // {"name": "iliakan", "isAdmin": true} }); ``` -The `response` object returned from `fetch` also includes the method `response.json()` that reads the remote data and parses it as JSON. In our case that's even more convenient, so let's switch to it. +`response` objektet der returneres fra `fetch` indeholder også metoden `response.json()` som læser de eksterne data og parser dem som JSON. I vores tilfælde er det endnu mere praktisk, så lad os skifte til det. -We'll also use arrow functions for brevity: +Vi vil også bruge arrow funktioner for at gøre koden kortere: ```js run -// same as above, but response.json() parses the remote content as JSON +// samme som ovenfor, men response.json() oversætter det hentede indhold som JSON fetch('/article/promise-chaining/user.json') .then(response => response.json()) - .then(user => alert(user.name)); // iliakan, got user name + .then(user => alert(user.name)); // iliakan, tog user.name ``` -Now let's do something with the loaded user. +Lad os gøre noget med den hentede bruger. -For instance, we can make one more request to GitHub, load the user profile and show the avatar: +For eksempel, vi kan lave et kald mere til GitHub, hente brugerens profil og vise en avatar: ```js run -// Make a request for user.json +// Opret en forespørgsel på user.json fetch('/article/promise-chaining/user.json') - // Load it as json + // Hent det ind som JSON .then(response => response.json()) - // Make a request to GitHub + // Lav en forespørgsel til GitHub .then(user => fetch(`https://api.github.com/users/${user.name}`)) - // Load the response as json + // Hent svaret som JSON .then(response => response.json()) - // Show the avatar image (githubUser.avatar_url) for 3 seconds (maybe animate it) + // Vis avatar billedet (githubUser.avatar_url) i 3 sekunder (måske animér det) .then(githubUser => { let img = document.createElement('img'); img.src = githubUser.avatar_url; @@ -287,13 +286,13 @@ fetch('/article/promise-chaining/user.json') }); ``` -The code works; see comments about the details. However, there's a potential problem in it, a typical error for those who begin to use promises. +Koden virker; se eventuelt kommentarer for flere detaljer. Men, der er et potentielt problem - en typisk fejl for dem, der begynder at bruge promises. -Look at the line `(*)`: how can we do something *after* the avatar has finished showing and gets removed? For instance, we'd like to show a form for editing that user or something else. As of now, there's no way. +Kig på linjen `(*)`: hvordan kan vi gøre noget *efter* at avataren er færdig med at blive vist og fjernet? Hvis vi for eksempel vil vise muligheder for at redigere brugeren eller noget i den stil. Som det er nu, er det ikke muligt. -To make the chain extendable, we need to return a promise that resolves when the avatar finishes showing. +For at kunne udvide kæden, må vi returnere en promise, der løses, når avataren er færdig med at blive vist. -Like this: +Som dette: ```js run fetch('/article/promise-chaining/user.json') @@ -315,15 +314,15 @@ fetch('/article/promise-chaining/user.json') */!* }, 3000); })) - // triggers after 3 seconds - .then(githubUser => alert(`Finished showing ${githubUser.name}`)); + // trigger efter 3 sekunder + .then(githubUser => alert(`Færdig med at vise ${githubUser.name}`)); ``` -That is, the `.then` handler in line `(*)` now returns `new Promise`, that becomes settled only after the call of `resolve(githubUser)` in `setTimeout` `(**)`. The next `.then` in the chain will wait for that. +Nu vil `.then` handleren i linje `(*)` returnere et `new Promise`, der først afsluttes efter kaldet til `resolve(githubUser)` i `setTimeout` `(**)`. Det næste `.then` i kæden vil vente på det. -As a good practice, an asynchronous action should always return a promise. That makes it possible to plan actions after it; even if we don't plan to extend the chain now, we may need it later. +Det er god praksis at en asynkron handling altid bør returnere et promise. Det gør det muligt at planlægge handlinger efter den; selv hvis vi ikke planlægger at udvide kæden nu, kan vi have brug for det senere. -Finally, we can split the code into reusable functions: +Endelig kan vi splitte koden op i funktioner der kan genbruges: ```js run function loadJson(url) { @@ -349,18 +348,18 @@ function showAvatar(githubUser) { }); } -// Use them: +// Brug dem således: loadJson('/article/promise-chaining/user.json') .then(user => loadGithubUser(user.name)) .then(showAvatar) - .then(githubUser => alert(`Finished showing ${githubUser.name}`)); + .then(githubUser => alert(`Færdig med at vise ${githubUser.name}`)); // ... ``` -## Summary +## Opsummering -If a `.then` (or `catch/finally`, doesn't matter) handler returns a promise, the rest of the chain waits until it settles. When it does, its result (or error) is passed further. +Hvis en `.then` (eller `catch/finally`, for den sags skyld) handler returnerer et promise, vil resten af kæden vente indtil den bliver løst. Når det sker, videregives resultatet (eller fejlen) videre. -Here's a full picture: +Her er et overbliksbillede: ![](promise-handler-variants.svg) diff --git a/1-js/11-async/03-promise-chaining/getMessage.js b/1-js/11-async/03-promise-chaining/getMessage.js index 6c589343..be48fdd5 100644 --- a/1-js/11-async/03-promise-chaining/getMessage.js +++ b/1-js/11-async/03-promise-chaining/getMessage.js @@ -1,3 +1,3 @@ function getMessage() { - return "Hello, world!"; + return "Hej, verden!"; } diff --git a/1-js/11-async/03-promise-chaining/promise-handler-variants.svg b/1-js/11-async/03-promise-chaining/promise-handler-variants.svg index 664a4dbe..749215f2 100644 --- a/1-js/11-async/03-promise-chaining/promise-handler-variants.svg +++ b/1-js/11-async/03-promise-chaining/promise-handler-variants.svg @@ -1 +1,116 @@ -return valuereturn promisethrow errorstate: "fulfilled" result: valuestate: "rejected" result: error...with the result of the new promise...state: "pending" result: undefinedthe call of .then(handler) always returns a promise:if handler ends with…that promise settles with: \ No newline at end of file + + + + + + + + + + + + + return value + + + return promise + + + throw error + + + + state: "fulfilled" + + result: value + + + + state: "rejected" + + result: error + + + + + + + ... med resultatet + + af et nyt promise... + + + + state: "pending" + + result: undefined + + + kaldet til .then(handler) returnerer altid et promise: + + + hvis handler ender med … + + + vil promise afslutte med: + + + + \ No newline at end of file From 5b035f030c32238de62552cee112cddfd5f274c0 Mon Sep 17 00:00:00 2001 From: ockley Date: Tue, 24 Mar 2026 11:03:55 +0100 Subject: [PATCH 17/21] Oversat --- .../01-error-async/solution.md | 8 +- .../01-error-async/task.md | 6 +- .../04-promise-error-handling/article.md | 132 +++++++++--------- 3 files changed, 73 insertions(+), 73 deletions(-) diff --git a/1-js/11-async/04-promise-error-handling/01-error-async/solution.md b/1-js/11-async/04-promise-error-handling/01-error-async/solution.md index 0d43f55e..a736bfa4 100644 --- a/1-js/11-async/04-promise-error-handling/01-error-async/solution.md +++ b/1-js/11-async/04-promise-error-handling/01-error-async/solution.md @@ -1,13 +1,13 @@ -The answer is: **no, it won't**: +Svaret er: **nej, det vil ikke**: ```js run new Promise(function(resolve, reject) { setTimeout(() => { - throw new Error("Whoops!"); + throw new Error("Ups!"); }, 1000); }).catch(alert); ``` -As said in the chapter, there's an "implicit `try..catch`" around the function code. So all synchronous errors are handled. +Som sagt tidligere i kapitlet er der en "implicit `try..catch`" omkring funktionens kode. Det betyder at alle synkrone fejl håndteres. -But here the error is generated not while the executor is running, but later. So the promise can't handle it. +Men her genereres fejlen ikke mens udføreren kører, men senere. Så promise kan ikke håndtere den. diff --git a/1-js/11-async/04-promise-error-handling/01-error-async/task.md b/1-js/11-async/04-promise-error-handling/01-error-async/task.md index bafc47ce..a5730166 100644 --- a/1-js/11-async/04-promise-error-handling/01-error-async/task.md +++ b/1-js/11-async/04-promise-error-handling/01-error-async/task.md @@ -1,11 +1,11 @@ -# Error in setTimeout +# Fejl i setTimeout -What do you think? Will the `.catch` trigger? Explain your answer. +Hvad tror du? Vil `.catch` blive udløst? Forklar dit svar. ```js new Promise(function(resolve, reject) { setTimeout(() => { - throw new Error("Whoops!"); + throw new Error("Ups!"); }, 1000); }).catch(alert); ``` diff --git a/1-js/11-async/04-promise-error-handling/article.md b/1-js/11-async/04-promise-error-handling/article.md index c5b4206a..10bd3626 100644 --- a/1-js/11-async/04-promise-error-handling/article.md +++ b/1-js/11-async/04-promise-error-handling/article.md @@ -1,21 +1,21 @@ -# Error handling with promises +# Håndtering af fejl med promises -Promise chains are great at error handling. When a promise rejects, the control jumps to the closest rejection handler. That's very convenient in practice. +Kæder af promise er gode til fejlbehandling. Når et promise afvises, springer kontrollen til den nærmeste afvisningshåndtering. Det er meget praktisk i praksis. -For instance, in the code below the URL to `fetch` is wrong (no such site) and `.catch` handles the error: +For eksempel, i koden nedenfor er URL'en til `fetch` forkert (ingen sådan side) og `.catch` håndterer fejlen: ```js run *!* -fetch('https://no-such-server.blabla') // rejects +fetch('https://no-such-server.blabla') // afviser */!* .then(response => response.json()) - .catch(err => alert(err)) // TypeError: failed to fetch (the text may vary) + .catch(err => alert(err)) // TypeError: failed to fetch (teksten kan variere) ``` -As you can see, the `.catch` doesn't have to be immediate. It may appear after one or maybe several `.then`. +Som du kan se behøver `.catch` ikke at komme umiddelbart efter. Den kan sagtens placeres efter en eller flere `.then`. -Or, maybe, everything is all right with the site, but the response is not valid JSON. The easiest way to catch all errors is to append `.catch` to the end of chain: +Eller, måske er alt i orden med siden, men svaret er ikke gyldigt JSON. Den nemmeste måde at fange alle fejl er at tilføje `.catch` til slutningen af kæden: ```js run fetch('/article/promise-chaining/user.json') @@ -38,168 +38,168 @@ fetch('/article/promise-chaining/user.json') */!* ``` -Normally, such `.catch` doesn't trigger at all. But if any of the promises above rejects (a network problem or invalid json or whatever), then it would catch it. +Normalt vil sådan en `.catch` slet ikke blive aktiveret. Men, hvis en af dine promises afvises (et netværksproblem, ugyldig json osv.), så vil den fange det. ## Implicit try..catch -The code of a promise executor and promise handlers has an "invisible `try..catch`" around it. If an exception happens, it gets caught and treated as a rejection. +Koden fra en promise udførerer og promise handlere har en "usynlig `try..catch`" omkring den. Hvis der sker en exception, vil den blive opfanget og behandlet som en afvisning. -For instance, this code: +Se for eksempel denne kode: ```js run new Promise((resolve, reject) => { *!* - throw new Error("Whoops!"); + throw new Error("Ups!"); */!* -}).catch(alert); // Error: Whoops! +}).catch(alert); // Error: Ups! ``` -...Works exactly the same as this: +...Virker præcis på samme måde som denne: ```js run new Promise((resolve, reject) => { *!* - reject(new Error("Whoops!")); + reject(new Error("Ups!")); */!* -}).catch(alert); // Error: Whoops! +}).catch(alert); // Error: Ups! ``` -The "invisible `try..catch`" around the executor automatically catches the error and turns it into rejected promise. +Den "usynlige `try..catch`" omkring udførerenopfanger automatisk fejl og omdanner dem til afviste løfter. -This happens not only in the executor function, but in its handlers as well. If we `throw` inside a `.then` handler, that means a rejected promise, so the control jumps to the nearest error handler. +Det sker ikke kun i udførerfunktionen, men også i dens handlere. Hvis vi bruger `throw` indeni en `.then`-handler, betyder det en afvisning af løftet, og kontrollen overgives til den nærmeste fejlhåndterer. -Here's an example: +Her er et eksempel: ```js run new Promise((resolve, reject) => { resolve("ok"); }).then((result) => { *!* - throw new Error("Whoops!"); // rejects the promise + throw new Error("Ups!"); // afviser løftet */!* -}).catch(alert); // Error: Whoops! +}).catch(alert); // Error: Ups! ``` -This happens for all errors, not just those caused by the `throw` statement. For example, a programming error: +Dette sker for alle fejl, ikke kun de der er forårsaget af `throw`-sætningen. For eksempel, en programmeringsfejl: ```js run new Promise((resolve, reject) => { resolve("ok"); }).then((result) => { *!* - blabla(); // no such function + blabla(); // funktionen findes ikke */!* -}).catch(alert); // ReferenceError: blabla is not defined +}).catch(alert); // ReferenceError: blabla er ikke defineret ``` -The final `.catch` not only catches explicit rejections, but also accidental errors in the handlers above. +Den endelige `.catch` fanger ikke kun eksplicitte afvigelser, men også tilfældige fejl i de håndteringer, der kommer før den. ## Rethrowing -As we already noticed, `.catch` at the end of the chain is similar to `try..catch`. We may have as many `.then` handlers as we want, and then use a single `.catch` at the end to handle errors in all of them. +Som vi allerede har bemærket ligner en `.catch` i slutningen af kæden `try..catch`. Vi kan have så mange `.then` håndteringer som vi vil, og så bruge en enkelt `.catch` i slutningen for at håndtere fejl i alle af dem. -In a regular `try..catch` we can analyze the error and maybe rethrow it if it can't be handled. The same thing is possible for promises. +I en normal `try..catch` kan vi analysere fejlen og måske kaste den igen, hvis den ikke kan håndteres. Det samme er muligt for promises. -If we `throw` inside `.catch`, then the control goes to the next closest error handler. And if we handle the error and finish normally, then it continues to the next closest successful `.then` handler. +Hvis vi bruger `throw` indeni `.catch`, så går kontrollen til den næste tætteste fejl-handler. Og hvis vi håndterer fejlen og afslutter normalt, så fortsætter det til den næste tætteste succesfulde `.then` handler. -In the example below the `.catch` successfully handles the error: +I eksemplet nedenfor håndterer `.catch` fejlen succesfuldt: ```js run // the execution: catch -> then new Promise((resolve, reject) => { - throw new Error("Whoops!"); + throw new Error("Ups!"); }).catch(function(error) { - alert("The error is handled, continue normally"); + alert("Fejlen er håndteret, fortsæt normalt"); -}).then(() => alert("Next successful handler runs")); +}).then(() => alert("Næste succesfulde handler kører")); ``` -Here the `.catch` block finishes normally. So the next successful `.then` handler is called. +Her afsluttes `.catch` blokken normalt. Så den næste succesfulde `.then` handler kaldes. -In the example below we see the other situation with `.catch`. The handler `(*)` catches the error and just can't handle it (e.g. it only knows how to handle `URIError`), so it throws it again: +I eksemplet nedenfor ser vi den anden situation med `.catch`. Handleren `(*)` fanger fejlen og kan ikke håndtere den (f.eks. den kun ved hvordan man håndterer `URIError`), så den kaster den igen: ```js run // the execution: catch -> catch new Promise((resolve, reject) => { - throw new Error("Whoops!"); + throw new Error("Ups!"); }).catch(function(error) { // (*) if (error instanceof URIError) { - // handle it + // håndter fejlen } else { - alert("Can't handle such error"); + alert("Kan ikke håndtere sådan en fejl"); *!* - throw error; // throwing this or another error jumps to the next catch + throw error; // kaster fejlen videre */!* } }).then(function() { - /* doesn't run here */ + /* denne handler kører ikke her */ }).catch(error => { // (**) - alert(`The unknown error has occurred: ${error}`); - // don't return anything => execution goes the normal way + alert(`En ukendt fejl er opstået: ${error}`); + // returnerer ikke noget => udførelse foregår normalt }); ``` -The execution jumps from the first `.catch` `(*)` to the next one `(**)` down the chain. +Udførelse foregår fra den første `.catch` `(*)` til den næste `(**)` ned ad kæden. -## Unhandled rejections +## Afvisninger der ikke håndteres -What happens when an error is not handled? For instance, we forgot to append `.catch` to the end of the chain, like here: +Hvad sker der når en fejl ikke håndteres? For eksempel, vi har glemt at tilføje `.catch` til slutningen af kæden, som her: ```js untrusted run refresh new Promise(function() { - noSuchFunction(); // Error here (no such function) + noSuchFunction(); // Fejl her (funktionen findes ikke) }) .then(() => { - // successful promise handlers, one or more - }); // without .catch at the end! + // håndtering af succesfuld promise, en eller flere + }); // men uden .catch i slutningen! ``` -In case of an error, the promise becomes rejected, and the execution should jump to the closest rejection handler. But there is none. So the error gets "stuck". There's no code to handle it. +I tilfælde af en fejl, bliver løftet afvist, og udførelsen vil prøve at hoppe til den nærmeste håndtering af afvisninger - men der er ingen. Så fejlen bliver "fastlåst". Der er ingen kode til at håndtere den. -In practice, just like with regular unhandled errors in code, it means that something has gone terribly wrong. +I praksis, ligesom med regulære uhåndterede fejl i kode, betyder det, at noget er gået frygteligt galt. -What happens when a regular error occurs and is not caught by `try..catch`? The script dies with a message in the console. A similar thing happens with unhandled promise rejections. +Hvad sker der når en regulær fejl opstår og ikke bliver fanget af `try..catch`? Scriptet dør med en besked i konsollen. Et lignende noget sker med uhåndterede promise-afvisninger. -The JavaScript engine tracks such rejections and generates a global error in that case. You can see it in the console if you run the example above. +JavaScript-motoren sporer sådanne afvisninger og genererer en global fejl i det tilfælde. Du kan se det i konsollen, hvis du kører eksemplet ovenfor. -In the browser we can catch such errors using the event `unhandledrejection`: +I browseren kan vi fange sådanne fejl ved hjælp af begivenheden `unhandledrejection`: ```js run *!* window.addEventListener('unhandledrejection', function(event) { - // the event object has two special properties: - alert(event.promise); // [object Promise] - the promise that generated the error - alert(event.reason); // Error: Whoops! - the unhandled error object + // et event objekt har to specielle egenskaber: + alert(event.promise); // [object Promise] - det promise der genererede fejlen + alert(event.reason); // Error: Ups! - det error objekt der ikke er behandlet }); */!* new Promise(function() { - throw new Error("Whoops!"); -}); // no catch to handle the error + throw new Error("Ups!"); +}); // ingen cathc til at opfange fejlen ``` -The event is the part of the [HTML standard](https://html.spec.whatwg.org/multipage/webappapis.html#unhandled-promise-rejections). +Event'et er en del af [HTML standarden](https://html.spec.whatwg.org/multipage/webappapis.html#unhandled-promise-rejections). -If an error occurs, and there's no `.catch`, the `unhandledrejection` handler triggers, and gets the `event` object with the information about the error, so we can do something. +Hvis der sker en fejl og der ikke er en `.catch`, vil handleren `unhandledrejection` blive udløst og modtage et `event` objekt med information om fejlen, så vi kan handle på det. -Usually such errors are unrecoverable, so our best way out is to inform the user about the problem and probably report the incident to the server. +Normalt er det ikke muligt at komme sig over sådanne fejl, så vores bedste måde at håndtere dem på er at informere brugeren om problemet og sandsynligvis rapportere hændelsen til serveren. -In non-browser environments like Node.js there are other ways to track unhandled errors. +I ikke-browser miljøer som Node.js findes der andre måder at spore uhåndterede fejl på. -## Summary +## Opsummering -- `.catch` handles errors in promises of all kinds: be it a `reject()` call, or an error thrown in a handler. -- `.then` also catches errors in the same manner, if given the second argument (which is the error handler). -- We should place `.catch` exactly in places where we want to handle errors and know how to handle them. The handler should analyze errors (custom error classes help) and rethrow unknown ones (maybe they are programming mistakes). -- It's ok not to use `.catch` at all, if there's no way to recover from an error. -- In any case we should have the `unhandledrejection` event handler (for browsers, and analogs for other environments) to track unhandled errors and inform the user (and probably our server) about them, so that our app never "just dies". +- `.catch` håndterer fejl i alle slags promises: det kan være en `reject()` der kaldes eller en fejl der kastes med `throw`. +- `.then` kan også opfange fejl på samme måde, hvis den får et andet argument (som er fejlhåndteringen). +- Vi bør placere `.catch` præcis på de steder vi vil håndtere fejlene og ved hvordan de skal behandles. Den handler der skal skal analysere fejlen (brugerdefinerede fejl kan hjælpe) og kaste fejl den ikke kender videre (rethrow) da det kan være programmeringsfejl. +- Det er ok slet ikke at bruge `.catch` hvis der ikke er nogen måde at afhjælpe fejl. +- I alle tilfælde bør vi have en `unhandledrejection` event handler (for browsere og tilsvarende for andre miljøer) til at opsnappe fejl der ikke håndteres og informere brugeren (og muligvis serveren) om dem, så vores app ikke bare "dør uden grund". From f0438247a759c7de31deefd5ab1948f0bee18c3e Mon Sep 17 00:00:00 2001 From: ockley Date: Tue, 24 Mar 2026 21:03:56 +0100 Subject: [PATCH 18/21] Oversat til dansk --- 1-js/11-async/05-promise-api/article.md | 162 ++++++++++++------------ 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/1-js/11-async/05-promise-api/article.md b/1-js/11-async/05-promise-api/article.md index 7be84ce2..b19af213 100644 --- a/1-js/11-async/05-promise-api/article.md +++ b/1-js/11-async/05-promise-api/article.md @@ -1,40 +1,40 @@ # Promise API -There are 6 static methods in the `Promise` class. We'll quickly cover their use cases here. +Der er 6 statiske metoder i `Promise` klassen. Vi gennemløber dem alle kort her. ## Promise.all -Let's say we want many promises to execute in parallel and wait until all of them are ready. +Lad os sige, vi vil have mange promises til at køre parallelt og vente til alle er klar. -For instance, download several URLs in parallel and process the content once they are all done. +Det kunnme for eksempel være at downloade flere URL'er og behandle indholdet når de alle er færdigindlæst. -That's what `Promise.all` is for. +Det er det `Promise.all` er til. -The syntax is: +Syntaksen er: ```js let promise = Promise.all(iterable); ``` -`Promise.all` takes an iterable (usually, an array of promises) and returns a new promise. +`Promise.all` tager et itererbart objekt (ofte et array af promises) og returnerer et nyt promise. -The new promise resolves when all listed promises are resolved, and the array of their results becomes its result. +Det nye promise løser sig når alle de listede promises er løst, og arrayet af deres resultater bliver dets result. -For instance, the `Promise.all` below settles after 3 seconds, and then its result is an array `[1, 2, 3]`: +For eksempel vil `Promise.all` nedenfor blive færdig efter 3 sekunder, og dens result er et array med indholdet `[1, 2, 3]`: ```js run Promise.all([ new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1 new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2 new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3 -]).then(alert); // 1,2,3 when promises are ready: each promise contributes an array member +]).then(alert); // 1,2,3 når løfterne er klare: hver promise bidrager med et array-element ``` -Please note that the order of the resulting array members is the same as in its source promises. Even though the first promise takes the longest time to resolve, it's still first in the array of results. +Bemærk at rækkefølgen for de resulterende array-elementer er den samme som i de oprindelige promises. Selvom den første promise tager længst tid at løse, er den stadig først i arrayet af resultater. -A common trick is to map an array of job data into an array of promises, and then wrap that into `Promise.all`. +Et meget udbredt tricket er at mappe et array af job-data til et array af promises, og så omslutte det i `Promise.all`. -For instance, if we have an array of URLs, we can fetch them all like this: +For eksempel, hvis vi har et array af URLs, kan vi hente dem alle sådan: ```js run let urls = [ @@ -43,17 +43,17 @@ let urls = [ 'https://api.github.com/users/jeresig' ]; -// map every url to the promise of the fetch +// map hver url til et promise fra fetch let requests = urls.map(url => fetch(url)); -// Promise.all waits until all jobs are resolved +// Promise.all venter til alle job er løst Promise.all(requests) .then(responses => responses.forEach( response => alert(`${response.url}: ${response.status}`) )); ``` -A bigger example with fetching user information for an array of GitHub users by their names (we could fetch an array of goods by their ids, the logic is identical): +Et større eksempel med hentning af brugerinformation for et array af GitHub-brugere efter deres navne (vi kunne hente et array af varer efter deres id, logikken er identisk): ```js run let names = ['iliakan', 'remy', 'jeresig']; @@ -62,47 +62,47 @@ let requests = names.map(name => fetch(`https://api.github.com/users/${name}`)); Promise.all(requests) .then(responses => { - // all responses are resolved successfully + // alle respons er løst for(let response of responses) { - alert(`${response.url}: ${response.status}`); // shows 200 for every url + alert(`${response.url}: ${response.status}`); // viser 200 for hver url } return responses; }) - // map array of responses into an array of response.json() to read their content + // map array af response til et array af response.json() til at læse deres indhold .then(responses => Promise.all(responses.map(r => r.json()))) - // all JSON answers are parsed: "users" is the array of them + // alle svar er oversat fra JSON: "users" objektet indeholder deres navn i "name" egenskaben .then(users => users.forEach(user => alert(user.name))); ``` -**If any of the promises is rejected, the promise returned by `Promise.all` immediately rejects with that error.** +**Hvis et af løfterne bliver afvist, bliver det promise der returneres af `Promise.all` umiddelbart afvist med den fejl.** -For instance: +For eksempel: ```js run Promise.all([ new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)), *!* - new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000)), + new Promise((resolve, reject) => setTimeout(() => reject(new Error("Ups!")), 2000)), */!* new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000)) -]).catch(alert); // Error: Whoops! +]).catch(alert); // Error: Ups! ``` -Here the second promise rejects in two seconds. That leads to an immediate rejection of `Promise.all`, so `.catch` executes: the rejection error becomes the outcome of the entire `Promise.all`. +Her bliver det andet promise afvist efter to sekunder. Det fører til en øjeblikkelig afvisning af `Promise.all`, så `.catch` eksekveres: fejlen bliver til resultatet af hele `Promise.all`. -```warn header="In case of an error, other promises are ignored" -If one promise rejects, `Promise.all` immediately rejects, completely forgetting about the other ones in the list. Their results are ignored. +```warn header="I tilfælde af en fejl, ignoreres andre promises" +Hvis et af løfterne bliver afvist, bliver det promise der returneres af `Promise.all` umiddelbart afvist med den fejl. Deres resultater ignoreres. -For example, if there are multiple `fetch` calls, like in the example above, and one fails, the others will still continue to execute, but `Promise.all` won't watch them anymore. They will probably settle, but their results will be ignored. +For eksempel, hvis der er flere `fetch` kald, som i eksemplet ovenfor, og ét af dem mislykkes, vil de andre stadig fortsætte med at køre, men `Promise.all` vil ikke længere holde øje med dem. De vil sandsynligvis slutte, men deres resultater vil blive ignoreret. -`Promise.all` does nothing to cancel them, as there's no concept of "cancellation" in promises. In [another chapter](info:fetch-abort) we'll cover `AbortController` that can help with that, but it's not a part of the Promise API. +`Promise.all` gør intet for at annullere dem, da der ikke er en koncept om "annullering" i promises. I [et andet kapitel](info:fetch-abort) vil vi dække `AbortController` som kan afhjælpe det, men det er ikke en del af Promise API'et. ``` -````smart header="`Promise.all(iterable)` allows non-promise \"regular\" values in `iterable`" -Normally, `Promise.all(...)` accepts an iterable (in most cases an array) of promises. But if any of those objects is not a promise, it's passed to the resulting array "as is". +````smart header="`Promise.all(itererbar)` tillader ikke-promise \"regulære\" værdier i `itererbar`" +Normalt accepterer, `Promise.all(...)` et itererbart objekt (ofte et array) med promises. Men, hvis nogle af disse objekter ikke er promises, bliver de overført til det resulterende array "som det er". -For instance, here the results are `[1, 2, 3]`: +Her er resultatet for eksempel `[1, 2, 3]`: ```js run Promise.all([ @@ -114,31 +114,31 @@ Promise.all([ ]).then(alert); // 1, 2, 3 ``` -So we are able to pass ready values to `Promise.all` where convenient. +Så vi er i stand til at overføre eksisterende værdier til `Promise.all` hvor det er praktisk. ```` ## Promise.allSettled [recent browser="new"] -`Promise.all` rejects as a whole if any promise rejects. That's good for "all or nothing" cases, when we need *all* results successful to proceed: +`Promise.all` fejler helt hvis bare ét af dets løfter afvises. Det er godt for "alt eller ingen" situationer, hvor vi har brug for at *alle* resultater er succesfulde for at fortsætte: ```js Promise.all([ fetch('/template.html'), fetch('/style.css'), fetch('/data.json') -]).then(render); // render method needs results of all fetches +]).then(render); // render metoden behøver resultaterne fra alle fetch kald ``` -`Promise.allSettled` just waits for all promises to settle, regardless of the result. The resulting array has: +`Promise.allSettled` venter på at alle løfter bliver løst, uanset resultatet. Det resulterende array har: -- `{status:"fulfilled", value:result}` for successful responses, -- `{status:"rejected", reason:error}` for errors. +- `{status:"fulfilled", value:result}` for succesfuldde løfter, og +- `{status:"rejected", reason:error}` for fejl. -For example, we'd like to fetch the information about multiple users. Even if one request fails, we're still interested in the others. +Det kunne for eksempel være, at vi gerne vil hente information om flere brugere. Selvom en forespørgsel mislykkes, er vi stadig interesseret i de andre. -Let's use `Promise.allSettled`: +Lad os bruge `Promise.allSettled`: ```js run let urls = [ @@ -160,7 +160,7 @@ Promise.allSettled(urls.map(url => fetch(url))) }); ``` -The `results` in the line `(*)` above will be: +`results` i linjen med `(*)` ovenfor vil være: ```js [ {status: 'fulfilled', value: ...response...}, @@ -169,11 +169,11 @@ The `results` in the line `(*)` above will be: ] ``` -So for each promise we get its status and `value/error`. +Så for hvert løfte får vi dens status og `value/error`. ### Polyfill -If the browser doesn't support `Promise.allSettled`, it's easy to polyfill: +Hvis browseren ikke understøtter `Promise.allSettled`, er det nemt at lave en polyfill: ```js if (!Promise.allSettled) { @@ -188,23 +188,23 @@ if (!Promise.allSettled) { } ``` -In this code, `promises.map` takes input values, turns them into promises (just in case a non-promise was passed) with `p => Promise.resolve(p)`, and then adds `.then` handler to every one. +I denne kode tager `promises.map` input værdierne og omdanner dem til promises (for en sikkerheds skyld, hvis der blev leveret et ikke-promise) med `p => Promise.resolve(p)`. Derefter tilføjes en `.then` til hver af dem. -That handler turns a successful result `value` into `{status:'fulfilled', value}`, and an error `reason` into `{status:'rejected', reason}`. That's exactly the format of `Promise.allSettled`. +Denne handler omdanner et succesfuldt resultats `value` til objektet `{status:'fulfilled', value}`, og en error `reason` om til `{status:'rejected', reason}`. Det er præcis det format, som `Promise.allSettled` forventes at levere. -Now we can use `Promise.allSettled` to get the results of *all* given promises, even if some of them reject. +Nu kan vi bruge `Promise.allSettled` til at give resultatet fra at hente resultaterne af *alle* givne promises, selvom nogle af dem afvises. ## Promise.race -Similar to `Promise.all`, but waits only for the first settled promise and gets its result (or error). +Minder om `Promise.all`, men venter kun på den første løste promise og får dens resultat (eller fejl). -The syntax is: +Syntaksen er: ```js -let promise = Promise.race(iterable); +let promise = Promise.race(itererbar); ``` -For instance, here the result will be `1`: +For eksempel vil resultatet her være `1`: ```js run Promise.race([ @@ -214,65 +214,65 @@ Promise.race([ ]).then(alert); // 1 ``` -The first promise here was fastest, so it became the result. After the first settled promise "wins the race", all further results/errors are ignored. +Det første promise her har hurtigst, så den bliver resultatet. Efter det første løste promise "vinder kapløbet" bliver alle de andre resultater og fejl ignoreret. ## Promise.any -Similar to `Promise.race`, but waits only for the first fulfilled promise and gets its result. If all of the given promises are rejected, then the returned promise is rejected with [`AggregateError`](mdn:js/AggregateError) - a special error object that stores all promise errors in its `errors` property. +Minder om `Promise.race`, men venter kun på den første *opfyldte* promise og får dens resultat. Hvis alle de givne promises er afvist, så er det returnerede promise afvist med [`AggregateError`](mdn:js/AggregateError) - et specielt error-objekt, der gemmer alle promise-fejl i sin `errors`-egenskab. -The syntax is: +Syntaksen er: ```js -let promise = Promise.any(iterable); +let promise = Promise.any(itererbar); ``` -For instance, here the result will be `1`: +For eksempel vil resultatet her være `1`: ```js run Promise.any([ - new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 1000)), + new Promise((resolve, reject) => setTimeout(() => reject(new Error("Ups!")), 1000)), new Promise((resolve, reject) => setTimeout(() => resolve(1), 2000)), new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000)) ]).then(alert); // 1 ``` -The first promise here was fastest, but it was rejected, so the second promise became the result. After the first fulfilled promise "wins the race", all further results are ignored. +Det første promise her har hurtigst, men det blev afvist, så det andet promise blev resultatet. Efter det første opfyldte promise "vinder kapløbet", bliver alle de andre resultater ignoreret. -Here's an example when all promises fail: +Her er et eksempel når alle promises fejler: ```js run Promise.any([ new Promise((resolve, reject) => setTimeout(() => reject(new Error("Ouch!")), 1000)), - new Promise((resolve, reject) => setTimeout(() => reject(new Error("Error!")), 2000)) + new Promise((resolve, reject) => setTimeout(() => reject(new Error("Fejl!")), 2000)) ]).catch(error => { console.log(error.constructor.name); // AggregateError console.log(error.errors[0]); // Error: Ouch! - console.log(error.errors[1]); // Error: Error! + console.log(error.errors[1]); // Error: Fejl! }); ``` -As you can see, error objects for failed promises are available in the `errors` property of the `AggregateError` object. +som du kan se, error objekter for fejlede løfter er tilgængelige i `errors`-egenskaben af `AggregateError`-objektet. ## Promise.resolve/reject -Methods `Promise.resolve` and `Promise.reject` are rarely needed in modern code, because `async/await` syntax (we'll cover it [a bit later](info:async-await)) makes them somewhat obsolete. +Metoderne `Promise.resolve` og `Promise.reject` er sjældent nødvendige i moderne kode, fordi `async/await` syntaksen (vi møder dem [lige om lidt](info:async-await)) gør dem lidt overflødige. -We cover them here for completeness and for those who can't use `async/await` for some reason. +Vi dækker dem her for fuldkommenhedens skyld og for de som ikke kan/vil bruge `async/await` af en eller anden grund. ### Promise.resolve -`Promise.resolve(value)` creates a resolved promise with the result `value`. +`Promise.resolve(value)` opretter et opfyldt promise med resultatet `value`. -Same as: +Det samme som: ```js let promise = new Promise(resolve => resolve(value)); ``` -The method is used for compatibility, when a function is expected to return a promise. +Metoden bruges til kompatibilitet, når en funktion forventes at returnere et promise. -For example, the `loadCached` function below fetches a URL and remembers (caches) its content. For future calls with the same URL it immediately gets the previous content from cache, but uses `Promise.resolve` to make a promise of it, so the returned value is always a promise: +For eksempel, funktionen `loadCached` nedenfor henter en URL og husker (cacher) dens indhold. For fremtidige opkald med samme URL får den øjeblikkeligt det tidligere indhold fra cachen, men bruger `Promise.resolve` til at lave et promise af det, så det returnerede værdi altid er et promise: ```js let cache = new Map(); @@ -293,31 +293,31 @@ function loadCached(url) { } ``` -We can write `loadCached(url).then(…)`, because the function is guaranteed to return a promise. We can always use `.then` after `loadCached`. That's the purpose of `Promise.resolve` in the line `(*)`. +Vi kan skrive `loadCached(url).then(…)`, fordi funktionen er garanteret til at returnere et promise. Vi kan altid bruge `.then` efter `loadCached`. Det er formålet med `Promise.resolve` i linjen `(*)`. ### Promise.reject -`Promise.reject(error)` creates a rejected promise with `error`. +`Promise.reject(error)` opretter et afvist promise med `error`. -Same as: +Det samme som: ```js let promise = new Promise((resolve, reject) => reject(error)); ``` -In practice, this method is almost never used. +I praksis bliver denne metode næsten aldrig brugt. -## Summary +## Opsummering -There are 6 static methods of `Promise` class: +Der er 6 statiske metoder i `Promise`-klassen: -1. `Promise.all(promises)` -- waits for all promises to resolve and returns an array of their results. If any of the given promises rejects, it becomes the error of `Promise.all`, and all other results are ignored. -2. `Promise.allSettled(promises)` (recently added method) -- waits for all promises to settle and returns their results as an array of objects with: - - `status`: `"fulfilled"` or `"rejected"` - - `value` (if fulfilled) or `reason` (if rejected). -3. `Promise.race(promises)` -- waits for the first promise to settle, and its result/error becomes the outcome. -4. `Promise.any(promises)` (recently added method) -- waits for the first promise to fulfill, and its result becomes the outcome. If all of the given promises are rejected, [`AggregateError`](mdn:js/AggregateError) becomes the error of `Promise.any`. -5. `Promise.resolve(value)` -- makes a resolved promise with the given value. -6. `Promise.reject(error)` -- makes a rejected promise with the given error. +1. `Promise.all(promises)` -- venter på at alle promises bliver opfyldt og returnerer en array med deres resultater. Hvis en af de givne promises bliver afvist, bliver det til fejlen i `Promise.all`, og alle andre resultater ignoreres. +2. `Promise.allSettled(promises)` (nylig tilføjet metode) -- venter på at alle promises bliver løst og returnerer deres resultater som en array af objekter med: + - `status`: `"fulfilled"` eller `"rejected"` + - `value` (hvis opfyldt) eller `reason` (hvis afvist). +3. `Promise.race(promises)` -- venter på at det første promise bliver løst (opfyldt eller afvist), og dets resultat/fejl bliver resultatet. +4. `Promise.any(promises)` -- venter på at det første promise bliver opfyldt, og dets resultaat bliver resultatet. Hvis alle de givne promises bliver afvist, bliver [`AggregateError`](mdn:js/AggregateError) til fejlen i `Promise.any`. +5. `Promise.resolve(value)` -- opretter et opfyldt promise med det givne værdi. +6. `Promise.reject(error)` -- opretter et afvist promise med det givne fejl. -Of all these, `Promise.all` is probably the most common in practice. +Af alle disse er `Promise.all` nok den mest brugte i praksis. From 5a036fa8b492622e0d222b73de68e634f8956b44 Mon Sep 17 00:00:00 2001 From: ockley Date: Tue, 24 Mar 2026 22:08:33 +0100 Subject: [PATCH 19/21] oversat til dansk --- 1-js/11-async/06-promisify/article.md | 73 ++++++++++++++------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/1-js/11-async/06-promisify/article.md b/1-js/11-async/06-promisify/article.md index 855678e5..2292d979 100644 --- a/1-js/11-async/06-promisify/article.md +++ b/1-js/11-async/06-promisify/article.md @@ -1,12 +1,12 @@ -# Promisification +# Promisificering -"Promisification" is a long word for a simple transformation. It's the conversion of a function that accepts a callback into a function that returns a promise. +"Promisificering" er et langt ord for en simpel transformation. Det er konverteringen af en function, der accepterer en callback, til en function, der returnerer et promise. -Such transformations are often required in real-life, as many functions and libraries are callback-based. But promises are more convenient, so it makes sense to promisify them. +Sådanne transformationer er ofte nødvendige i det virkelige liv, da mange funktioner og biblioteker er callback-baserede. Men promises er mere praktiske, så det giver mening at promisificere dem. -For better understanding, let's see an example. +For bedre at forstå det så lad os se et ekssempel. -For instance, we have `loadScript(src, callback)` from the chapter . +Her er for eksempel `loadScript(src, callback)` fra kapitlet . ```js run function loadScript(src, callback) { @@ -19,19 +19,19 @@ function loadScript(src, callback) { document.head.append(script); } -// usage: +// brug: // loadScript('path/script.js', (err, script) => {...}) ``` -The function loads a script with the given `src`, and then calls `callback(err)` in case of an error, or `callback(null, script)` in case of successful loading. That's a widespread agreement for using callbacks, we saw it before. +Funktionen henter et script der gives med `src`, og så kalder den `callback(err)` i tilfælde af en fejl, eller `callback(null, script)` i tilfælde af succesfuld indlæsning. Det er en almindelig overenskomst for brug af callbacks, som vi har set før. -Let's promisify it. +Lad os promisificere det. -We'll make a new function `loadScriptPromise(src)`, that does the same (loads the script), but returns a promise instead of using callbacks. +Vi vil lave en ny function `loadScriptPromise(src)`, som gør det samme (henter scriptet), men returnerer et promise i stedet for at bruge callbacks. -In other words, we pass it only `src` (no `callback`) and get a promise in return, that resolves with `script` when the load is successful, and rejects with the error otherwise. +Med andre ord, vi sender kun `src` (ingen `callback`) og får et promise tilbage, som løser sig med `script` når indlæsningen er successful, og afvises med fejlen ellers. -Here it is: +Her er det: ```js let loadScriptPromise = function(src) { return new Promise((resolve, reject) => { @@ -42,23 +42,23 @@ let loadScriptPromise = function(src) { }); }; -// usage: +// brug: // loadScriptPromise('path/script.js').then(...) ``` -As we can see, the new function is a wrapper around the original `loadScript` function. It calls it providing its own callback that translates to promise `resolve/reject`. +Som vi kan se er den nye function en wrapper omkring den originale `loadScript` function. Den kalder den og giver sin egen callback, som oversætter til et promise med `resolve/reject`. -Now `loadScriptPromise` fits well in promise-based code. If we like promises more than callbacks (and soon we'll see more reasons for that), then we will use it instead. +Nu passer `loadScriptPromise` ind i promise-baseret kode. Hvis vi kan lide promises bedre end callbacks (og senere vil vi se flere grunde for det), så kan vi bruge den i stedet. -In practice we may need to promisify more than one function, so it makes sense to use a helper. +I praksis vil vi måske have brug for at promisificere flere funktioner, så det giver mening at bruge en hjælper funktion. -We'll call it `promisify(f)`: it accepts a to-promisify function `f` and returns a wrapper function. +Vi vil kalde den `promisify(f)`: den accepterer en function `f` der skal promisificeres og returnerer en wrapper function. ```js function promisify(f) { - return function (...args) { // return a wrapper-function (*) + return function (...args) { // returner en wrapper-funktion (*) return new Promise((resolve, reject) => { - function callback(err, result) { // our custom callback for f (**) + function callback(err, result) { // vores brugerdefinerede callback til f (**) if (err) { reject(err); } else { @@ -66,9 +66,9 @@ function promisify(f) { } } - args.push(callback); // append our custom callback to the end of f arguments + args.push(callback); // tilføj vores brugerdefinerede callback til slutningen af f's argumenter - f.call(this, ...args); // call the original function + f.call(this, ...args); // kald den originale funktion }); }; } @@ -78,29 +78,30 @@ let loadScriptPromise = promisify(loadScript); loadScriptPromise(...).then(...); ``` -The code may look a bit complex, but it's essentially the same that we wrote above, while promisifying `loadScript` function. +Koden kan se lidt kompleks ud, men det er grundlæggende det samme, som vi skrev ovenfor, da vi promisificerede `loadScript` funktionen. -A call to `promisify(f)` returns a wrapper around `f` `(*)`. That wrapper returns a promise and forwards the call to the original `f`, tracking the result in the custom callback `(**)`. +Et kald til `promisify(f)` returnerer en wrapper omkring `f` `(*)`. Den wrapper returnerer et promise og videreformidler kaldet til den originale `f`, som sporer resultatet i den brugerdefinerede callback `(**)`. -Here, `promisify` assumes that the original function expects a callback with exactly two arguments `(err, result)`. That's what we encounter most often. Then our custom callback is in exactly the right format, and `promisify` works great for such a case. +Her regner `promisify` med at den originale funktion forventer en callback med præcis to argumenter `(err, result)`. Det er det, vi oftest støder på. Så vores brugerdefinerede callback er i præcis det rigtige format, og `promisify` virker godt for sådanne tilfælde. -But what if the original `f` expects a callback with more arguments `callback(err, res1, res2, ...)`? +Men hvad hvis den originale `f` forventer en callback med flere argumenter `callback(err, res1, res2, ...)`? -We can improve our helper. Let's make a more advanced version of `promisify`. +Vi kan forbedre vores hjælper. Lad os lave en mere avanceret version af `promisify`. -- When called as `promisify(f)` it should work similar to the version above. -- When called as `promisify(f, true)`, it should return the promise that resolves with the array of callback results. That's exactly for callbacks with many arguments. +- Når den kaldes som `promisify(f)` bør den fungere ligesom versionen ovenfor. +- Når den kaldes som `promisify(f, true)`, bør den returnere det promise, der løser sig med arrayet af callback-resultater. Det er netop til brug for callbacks med mange argumenter. ```js -// promisify(f, true) to get array of results +// promisify(f, true) for at få et array af resultater function promisify(f, manyArgs = false) { return function (...args) { return new Promise((resolve, reject) => { - function *!*callback(err, ...results*/!*) { // our custom callback for f + function *!*callback(err, ...results*/!*) { // vores brugerdefinrerede callback for f if (err) { reject(err); } else { - // resolve with all callback results if manyArgs is specified + // resolve med array af alle callback-resultater hvis manyArgs er specificeret, + // ellers resolve med det første resultat *!*resolve(manyArgs ? results : results[0]);*/!* } } @@ -117,16 +118,16 @@ f = promisify(f, true); f(...).then(arrayOfResults => ..., err => ...); ``` -As you can see it's essentially the same as above, but `resolve` is called with only one or all arguments depending on whether `manyArgs` is truthy. +Som du kan se er det stort set det samme som ovenfor, men `resolve` kaldes med kun ét eller alle argumenter afhængigt af om `manyArgs` er sand. -For more exotic callback formats, like those without `err` at all: `callback(result)`, we can promisify such functions manually without using the helper. +For mere eksotiske callback-formater, som dem uden `err` overhovedet: `callback(result)`, kan vi promisificere sådanne funktioner manuelt uden at bruge hjælperen. -There are also modules with a bit more flexible promisification functions, e.g. [es6-promisify](https://github.com/digitaldesignlabs/es6-promisify). In Node.js, there's a built-in `util.promisify` function for that. +Der er også moduler med lidt mere fleksible promisification-funktioner, f.eks. [es6-promisify](https://github.com/digitaldesignlabs/es6-promisify). I Node.js er der en indbygget `util.promisify`-funktion til det. ```smart -Promisification is a great approach, especially when you use `async/await` (covered later in the chapter ), but not a total replacement for callbacks. +Promisificering er at god tilgang, særligt hvis du bruger `async/await` (som vi viser senere i kapitlet ), men ikke ment som en total erstatning for callbacks. -Remember, a promise may have only one result, but a callback may technically be called many times. +Husk, at et promise kun kan have ét resultat, mens en callback teknisk set kan kaldes mange gange. -So promisification is only meant for functions that call the callback once. Further calls will be ignored. +Så promisificering er kun ment til funktioner, der kalder callback'en én gang. Yderligere kald vil blive ignoreret. ``` From b0fdbd3fbc8d2509839b4a07007b08d838504197 Mon Sep 17 00:00:00 2001 From: ockley Date: Tue, 24 Mar 2026 22:34:27 +0100 Subject: [PATCH 20/21] Oversat til dansk --- 1-js/11-async/07-microtask-queue/article.md | 90 +++++++++---------- .../07-microtask-queue/promiseQueue.svg | 82 ++++++++++++++++- 2 files changed, 126 insertions(+), 46 deletions(-) diff --git a/1-js/11-async/07-microtask-queue/article.md b/1-js/11-async/07-microtask-queue/article.md index 014dd93c..47cbe0d2 100644 --- a/1-js/11-async/07-microtask-queue/article.md +++ b/1-js/11-async/07-microtask-queue/article.md @@ -1,112 +1,112 @@ # Microtasks -Promise handlers `.then`/`.catch`/`.finally` are always asynchronous. +Promise handlers `.then`/`.catch`/`.finally` er altid asynkrone. -Even when a Promise is immediately resolved, the code on the lines *below* `.then`/`.catch`/`.finally` will still execute before these handlers. +Selv når et promise løses umiddelbart, vil koden på linjerne *under* `.then`/`.catch`/`.finally` stadig køre før disse handlers. -Here's a demo: +Her er et eksempel: ```js run let promise = Promise.resolve(); -promise.then(() => alert("promise done!")); +promise.then(() => alert("promise færdig!")); -alert("code finished"); // this alert shows first +alert("kode færdig"); // denne kode vises først ``` -If you run it, you see `code finished` first, and then `promise done!`. +Hvis du kører det, ser du `kode færdig` først, og så `promise færdig!`. -That's strange, because the promise is definitely done from the beginning. +Det er mærkeligt, fordi promise er helt sikkert færdig fra starten. -Why did the `.then` trigger afterwards? What's going on? +Hvorfor aktiverede `.then` efterfølgende? Hvad sker der? ## Microtasks queue -Asynchronous tasks need proper management. For that, the ECMA standard specifies an internal queue `PromiseJobs`, more often referred to as the "microtask queue" (V8 term). +Asynkrone opgaver har brug for korrekt håndtering. Til det formål specificerer ECMA-standarden en intern kø `PromiseJobs`, som ofte refereres til som "microtask queue" (V8 term). -As stated in the [specification](https://tc39.github.io/ecma262/#sec-jobs-and-job-queues): +Som angivet i [specifikationen](https://tc39.github.io/ecma262/#sec-jobs-and-job-queues): -- The queue is first-in-first-out: tasks enqueued first are run first. -- Execution of a task is initiated only when nothing else is running. +- Køen er first-in-first-out: opgaver, der er sat i køen først, køres først. +- Udførelse af en opgave initieres kun, når intet andet er i gang. -Or, to put it more simply, when a promise is ready, its `.then/catch/finally` handlers are put into the queue; they are not executed yet. When the JavaScript engine becomes free from the current code, it takes a task from the queue and executes it. +Eller, sagt på en simpel måde, når et promise er færdigt, bliver dets `.then/catch/finally` handlers sat i køen; de bliver ikke udført endnu. Når JavaScript-motoren bliver ledig fra den nuværende kode, tager den en opgave fra køen og udfører den. -That's why "code finished" in the example above shows first. +Det er derfor "kode færdig" i eksemplet ovenfor vises først. ![](promiseQueue.svg) -Promise handlers always go through this internal queue. +Promise handlers går altid gennem denne interne kø. -If there's a chain with multiple `.then/catch/finally`, then every one of them is executed asynchronously. That is, it first gets queued, then executed when the current code is complete and previously queued handlers are finished. +Hvis der er en kæde med flere `.then/catch/finally`, så udføres hver enkelt asynkront. Det vil sige, at de først sættes i køen, og derefter udføres, når den nuværende kode er færdig og tidligere satte handlers er færdige. -**What if the order matters for us? How can we make `code finished` appear after `promise done`?** +**Hvad hvis rækkefølgen er vigtig for os? Hvordan kan vi få `kode færdig` til at vises efter `promise færdig`?** -Easy, just put it into the queue with `.then`: +Simpelthen ved at putte det i køen med `.then`: ```js run Promise.resolve() - .then(() => alert("promise done!")) - .then(() => alert("code finished")); + .then(() => alert("promise færdig!")) + .then(() => alert("kode færdig")); ``` -Now the order is as intended. +Nu er rækkefølgen som ønsket. -## Unhandled rejection +## Uhåndteret afvisning -Remember the `unhandledrejection` event from the article ? +Husker du `unhandledrejection` eventen fra artiklen ? -Now we can see exactly how JavaScript finds out that there was an unhandled rejection. +Nu kan vi se præcis hvordan JavaScript finder ud af, at der er en uhåndteret afvisning. -**An "unhandled rejection" occurs when a promise error is not handled at the end of the microtask queue.** +**En "uhåndteret afvisning" opstår, når en promise fejl ikke håndteres i slutningen af microtask-køen.** -Normally, if we expect an error, we add `.catch` to the promise chain to handle it: +Normalt, hvis vi forventer en fejl, tilføjer vi `.catch` til promise-kæden for at håndtere den: ```js run -let promise = Promise.reject(new Error("Promise Failed!")); +let promise = Promise.reject(new Error("Promise fejlet!")); *!* -promise.catch(err => alert('caught')); +promise.catch(err => alert('fanget')); */!* -// doesn't run: error handled +// kører ikke: fejlen er håndteret window.addEventListener('unhandledrejection', event => alert(event.reason)); ``` -But if we forget to add `.catch`, then, after the microtask queue is empty, the engine triggers the event: +Men hvis vi glemmer at tilføje `.catch`, så udløser motoren eventet, efter at microtask-køen er tom, og den ser, at der er en promise i "afvist" tilstand: ```js run -let promise = Promise.reject(new Error("Promise Failed!")); +let promise = Promise.reject(new Error("Promise fejlet!")); -// Promise Failed! +// Promise fejlet! window.addEventListener('unhandledrejection', event => alert(event.reason)); ``` -What if we handle the error later? Like this: +Hvad hvis vi håndterer fejlen senere? Sådan her: ```js run -let promise = Promise.reject(new Error("Promise Failed!")); +let promise = Promise.reject(new Error("Promise fejlet!")); *!* -setTimeout(() => promise.catch(err => alert('caught')), 1000); +setTimeout(() => promise.catch(err => alert('fanget')), 1000); */!* -// Error: Promise Failed! +// Error: Promise fejlet! window.addEventListener('unhandledrejection', event => alert(event.reason)); ``` -Now, if we run it, we'll see `Promise Failed!` first and then `caught`. +Hvis vi kører koden vil vi se `Promise fejlet!` først og derefter `fanget`. -If we didn't know about the microtasks queue, we could wonder: "Why did `unhandledrejection` handler run? We did catch and handle the error!" +Hvis vi ikke kendte til microtasks-køen, kunne vi undre os: "Hvorfor kørte `unhandledrejection` handleren? Vi fangede og håndterede fejlen!" -But now we understand that `unhandledrejection` is generated when the microtask queue is complete: the engine examines promises and, if any of them is in the "rejected" state, then the event triggers. +Men nu forstår vi, at `unhandledrejection` genereres, når microtask-køen er tom: motoren undersøger promises, og hvis en af dem er i "rejected" tilstand, så udløser eventet. -In the example above, `.catch` added by `setTimeout` also triggers. But it does so later, after `unhandledrejection` has already occurred, so it doesn't change anything. +I eksemplet ovenfor kan vi se et `.catch` blive tilføjet af `setTimeout` som også udløses - men det sker senere. På det tidspunkt er `unhandledrejection` allerede opstået, så det ændrer ikke på noget. -## Summary +## Opsummering -Promise handling is always asynchronous, as all promise actions pass through the internal "promise jobs" queue, also called "microtask queue" (V8 term). +Håndtering af promises er altid asynkron, da alle promise-handlinger går gennem den interne "promise jobs" kø, også kaldet "microtask kø" (V8 term). -So `.then/catch/finally` handlers are always called after the current code is finished. +Så `.then/catch/finally` handlers kaldes altid efter, at den nuværende kode er færdig. -If we need to guarantee that a piece of code is executed after `.then/catch/finally`, we can add it into a chained `.then` call. +Hvis vi har brug for at garantere, at en del af koden bliver udført efter `.then/catch/finally`, kan vi tilføje den til en kædet `.then` kald. -In most Javascript engines, including browsers and Node.js, the concept of microtasks is closely tied with the "event loop" and "macrotasks". As these have no direct relation to promises, they are covered in another part of the tutorial, in the article . +I de fleste Javascript motorer, inklusiv browsere og Node.js, er konceptet microtasks tæt forbundet med "event loop" og "macrotasks". Da disse ikke har en direkte relation til promises, er de behandlet i en anden del af tutorialen, i artiklen . diff --git a/1-js/11-async/07-microtask-queue/promiseQueue.svg b/1-js/11-async/07-microtask-queue/promiseQueue.svg index c802c44a..fbc635c7 100644 --- a/1-js/11-async/07-microtask-queue/promiseQueue.svg +++ b/1-js/11-async/07-microtask-queue/promiseQueue.svg @@ -1 +1,81 @@ -promise . then ( handler ); ... alert ( "code finished" );handler enqueuedqueued handler runsscript execution finished \ No newline at end of file + + + + + + + + + + promise + . + then + ( + handler + ); + ... + alert + ( + "kode færdig" + ); + + + + handler sat i kø + + + handlere i kø afvikles + + + + + + + script udførsel færdig + + + + + \ No newline at end of file From b78ad5b9faa0f195caaba0ffe2f16999e6097177 Mon Sep 17 00:00:00 2001 From: ockley Date: Wed, 25 Mar 2026 00:31:19 +0100 Subject: [PATCH 21/21] Oversat til dansk --- .../01-rewrite-async/solution.md | 14 +- .../08-async-await/01-rewrite-async/task.md | 4 +- .../02-rewrite-async-2/solution.md | 16 +- .../08-async-await/02-rewrite-async-2/task.md | 14 +- .../03-async-from-regular/solution.md | 7 +- .../03-async-from-regular/task.md | 12 +- .../04-promise-all-failure/solution.md | 48 +++--- .../04-promise-all-failure/task.md | 38 ++--- 1-js/11-async/08-async-await/article.md | 144 +++++++++--------- 9 files changed, 149 insertions(+), 148 deletions(-) diff --git a/1-js/11-async/08-async-await/01-rewrite-async/solution.md b/1-js/11-async/08-async-await/01-rewrite-async/solution.md index 3337ef3c..c429b310 100644 --- a/1-js/11-async/08-async-await/01-rewrite-async/solution.md +++ b/1-js/11-async/08-async-await/01-rewrite-async/solution.md @@ -1,5 +1,5 @@ -The notes are below the code: +Noterne er under koden: ```js run async function loadJson(url) { // (1) @@ -17,11 +17,11 @@ 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) { @@ -29,5 +29,5 @@ Notes: } ``` - 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. diff --git a/1-js/11-async/08-async-await/01-rewrite-async/task.md b/1-js/11-async/08-async-await/01-rewrite-async/task.md index 0c31737d..5d057483 100644 --- a/1-js/11-async/08-async-await/01-rewrite-async/task.md +++ b/1-js/11-async/08-async-await/01-rewrite-async/task.md @@ -1,7 +1,7 @@ -# Rewrite using async/await +# Omskriv ved brug af async/await -Rewrite this example code from the chapter using `async/await` instead of `.then/catch`: +Omskriv dette eksempelkode fra kapitlet ved hjælp af `async/await` i stedet for `.then/catch`: ```js run function loadJson(url) { diff --git a/1-js/11-async/08-async-await/02-rewrite-async-2/solution.md b/1-js/11-async/08-async-await/02-rewrite-async-2/solution.md index aa462dbf..8826237d 100644 --- a/1-js/11-async/08-async-await/02-rewrite-async-2/solution.md +++ b/1-js/11-async/08-async-await/02-rewrite-async-2/solution.md @@ -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 { @@ -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; } diff --git a/1-js/11-async/08-async-await/02-rewrite-async-2/task.md b/1-js/11-async/08-async-await/02-rewrite-async-2/task.md index 13d625d2..39708ee3 100644 --- a/1-js/11-async/08-async-await/02-rewrite-async-2/task.md +++ b/1-js/11-async/08-async-await/02-rewrite-async-2/task.md @@ -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 { @@ -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; diff --git a/1-js/11-async/08-async-await/03-async-from-regular/solution.md b/1-js/11-async/08-async-await/03-async-from-regular/solution.md index 7e2ab597..ce5151d4 100644 --- a/1-js/11-async/08-async-await/03-async-from-regular/solution.md +++ b/1-js/11-async/08-async-await/03-async-from-regular/solution.md @@ -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)); @@ -10,7 +11,7 @@ async function wait() { } function f() { - // shows 10 after 1 second + // viser 10 efter 1 sekund *!* wait().then(result => alert(result)); */!* diff --git a/1-js/11-async/08-async-await/03-async-from-regular/task.md b/1-js/11-async/08-async-await/03-async-from-regular/task.md index ca7c186f..e6f97e30 100644 --- a/1-js/11-async/08-async-await/03-async-from-regular/task.md +++ b/1-js/11-async/08-async-await/03-async-from-regular/task.md @@ -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() { @@ -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. diff --git a/1-js/11-async/08-async-await/04-promise-all-failure/solution.md b/1-js/11-async/08-async-await/04-promise-all-failure/solution.md index 9fda8e00..134d1adc 100644 --- a/1-js/11-async/08-async-await/04-promise-all-failure/solution.md +++ b/1-js/11-async/08-async-await/04-promise-all-failure/solution.md @@ -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) { @@ -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 = []; @@ -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; diff --git a/1-js/11-async/08-async-await/04-promise-all-failure/task.md b/1-js/11-async/08-async-await/04-promise-all-failure/task.md index 74571c43..6b6b4773 100644 --- a/1-js/11-async/08-async-await/04-promise-all-failure/task.md +++ b/1-js/11-async/08-async-await/04-promise-all-failure/task.md @@ -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; @@ -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); @@ -54,8 +54,8 @@ 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), @@ -63,7 +63,7 @@ async function run() { */!* ]); } catch(error) { - console.log('Error handled (or was it?)'); + console.log('Fejl håndteret (eller er den?)'); } disconnect(); @@ -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? \ No newline at end of file +Hvorfor? Hvordan undgår man det? \ No newline at end of file diff --git a/1-js/11-async/08-async-await/article.md b/1-js/11-async/08-async-await/article.md index e679b1c4..c83b794a 100644 --- a/1-js/11-async/08-async-await/article.md +++ b/1-js/11-async/08-async-await/article.md @@ -1,10 +1,10 @@ # Async/await -There's a special syntax to work with promises in a more comfortable fashion, called "async/await". It's surprisingly easy to understand and use. +Der er en speciel syntaks der bruges til at arbejde med promises på en mere komfortabel måde, kaldet "async/await". Den er overraskende let at forstå og bruge. ## Async functions -Let's start with the `async` keyword. It can be placed before a function, like this: +Lad os starte med nøgleordet `async`. Det kan placeres før en function, sådan her: ```js async function f() { @@ -12,9 +12,9 @@ async function f() { } ``` -The word "async" before a function means one simple thing: a function always returns a promise. Other values are wrapped in a resolved promise automatically. +Ordet "async" før en function betyder en simpel ting: en function returnerer altid en promise. Andre værdier er automatisk pakket ind i en løst (resolved) promise. -For instance, this function returns a resolved promise with the result of `1`; let's test it: +For eksempel, denne funktion returnerer et løst promise med resultatet `1`; lad os teste den: ```js run async function f() { @@ -24,7 +24,7 @@ async function f() { f().then(alert); // 1 ``` -...We could explicitly return a promise, which would be the same: +... vi kunne også eksplicit returnere et promise, hvilket ville være det samme: ```js run async function f() { @@ -34,20 +34,20 @@ async function f() { f().then(alert); // 1 ``` -So, `async` ensures that the function returns a promise, and wraps non-promises in it. Simple enough, right? But not only that. There's another keyword, `await`, that works only inside `async` functions, and it's pretty cool. +Så `async` sikrer at funktionen returnerer et promise, og pakker ikke-promise værdier ind i et løst promise. Enkelt nok, ikke? Men ikke kun det. Der er endnu et nøgleord, `await`, som kun virker inde i `async` funktioner, og det er ret sejt. ## Await -The syntax: +Syntaksen er: ```js -// works only inside async functions +// virker kun inde i async funktioner let value = await promise; ``` -The keyword `await` makes JavaScript wait until that promise settles and returns its result. +Nøgleordet `await` gør at JavaScript venter indtil det promise er løst og returnerer dets resultat. -Here's an example with a promise that resolves in 1 second: +Her er et eksempel med et promise, der løses om 1 sekund: ```js run async function f() { @@ -56,23 +56,23 @@ async function f() { }); *!* - let result = await promise; // wait until the promise resolves (*) + let result = await promise; // vent indtil promise løses (*) */!* - alert(result); // "done!" + alert(result); // "færdig!" } f(); ``` -The function execution "pauses" at the line `(*)` and resumes when the promise settles, with `result` becoming its result. So the code above shows "done!" in one second. +Udførelsen af funktionen "sættes på pause" ved linjen `(*)` og fortsætter når promise løses, med `result` som dens resultat. Koden ovenfor vil vise "færdig!" efter 1 sekund. -Let's emphasize: `await` literally suspends the function execution until the promise settles, and then resumes it with the promise result. That doesn't cost any CPU resources, because the JavaScript engine can do other jobs in the meantime: execute other scripts, handle events, etc. +Lad os understrege: `await` udsætter eksekvering af funktionen indtil promise løses og fortsætter med det modtagne resultat. Det koster ikke nogen CPU ressourcer, fordi JavaScript motoren kan udføre andre job i mellemtiden: udføre andre scripts, håndtere events etc. -It's just a more elegant syntax of getting the promise result than `promise.then`. And, it's easier to read and write. +Det er bare en mere elegant syntaks for at få resultatet af et promise end `promise.then`. Og det er lettere at læse og skrive. -````warn header="Can't use `await` in regular functions" -If we try to use `await` in a non-async function, there would be a syntax error: +````warn header="Du kan ikke bruge `await` i regulære funktioner" +HVis vi prøver at bruge `await` i en ikke-async funktion, vil der være en syntaxfejl: ```js run function f() { @@ -83,32 +83,32 @@ function f() { } ``` -We may get this error if we forget to put `async` before a function. As stated earlier, `await` only works inside an `async` function. +Vi får den fejl hvis vi glemmer at tilføje `async` før en funktion. Som nævnt tidligere, virker `await` kun inde i en `async` funktion. ```` -Let's take the `showAvatar()` example from the chapter and rewrite it using `async/await`: +Lad os tage `showAvatar()` eksemplet fra kapitlet og omskrive det ved hjælp af `async/await`: -1. We'll need to replace `.then` calls with `await`. -2. Also we should make the function `async` for them to work. +1. Vi vil skulle erstatte `.then` kald med `await`. +2. Desuden bør vi gøre funktionen `async` for at de kan fungere. ```js run async function showAvatar() { - // read our JSON + // læs JSON filen let response = await fetch('/article/promise-chaining/user.json'); let user = await response.json(); - // read github user + // læs github bruger let githubResponse = await fetch(`https://api.github.com/users/${user.name}`); let githubUser = await githubResponse.json(); - // show the avatar + // vis avatar let img = document.createElement('img'); img.src = githubUser.avatar_url; img.className = "promise-avatar-example"; document.body.append(img); - // wait 3 seconds + // vent 3 sekunder await new Promise((resolve, reject) => setTimeout(resolve, 3000)); img.remove(); @@ -119,24 +119,24 @@ async function showAvatar() { showAvatar(); ``` -Pretty clean and easy to read, right? Much better than before. +Ret rent og nemt at læse, ikke? Meget bedre end før. -````smart header="Modern browsers allow top-level `await` in modules" -In modern browsers, `await` on top level works just fine, when we're inside a module. We'll cover modules in article . +````smart header="Moderne browsere tillader top-level `await` i moduler" +I moderne browsere vil `await` på top level fungere helt fint, når vi er inde i et modul. Vi vil dække moduler i artiklen . -For instance: +For eksempel: ```js run module -// we assume this code runs at top level, inside a module +// vi tager udgangspunkt i, at denne kode kører på top level, inde i et modul let response = await fetch('/article/promise-chaining/user.json'); let user = await response.json(); console.log(user); ``` -If we're not using modules, or [older browsers](https://caniuse.com/mdn-javascript_operators_await_top_level) must be supported, there's a universal recipe: wrapping into an anonymous async function. +Hvis vi ikke bruger moduler, eller [ældre browsere](https://caniuse.com/mdn-javascript_operators_await_top_level) skal understøttes, er der en universel opskrift: pak det hele ind i en anonym async funktion. -Like this: +Sådan her: ```js (async () => { @@ -148,10 +148,10 @@ Like this: ```` -````smart header="`await` accepts \"thenables\"" -Like `promise.then`, `await` allows us to use thenable objects (those with a callable `then` method). The idea is that a third-party object may not be a promise, but promise-compatible: if it supports `.then`, that's enough to use it with `await`. +````smart header="`await` accepterer \"thenables\"" +Ligesom `promise.then` vil `await` tillade os at bruge *thenable* objekter (dem med en meode `then` der kan kaldes). Idéen med dette er at 3de-parts objekter ikke nødvendigvis er et promise, men promise-kompatible: hvis det understøtter `.then`, er det godt nok til at bruge sammen med `await`. -Here's a demo `Thenable` class; the `await` below accepts its instances: +Her er en demo `Thenable` klasse; `await` nedenfor accepterer udgaver af den: ```js run class Thenable { @@ -160,13 +160,13 @@ class Thenable { } then(resolve, reject) { alert(resolve); - // resolve with this.num*2 after 1000ms + // resolve med this.num*2 efter 1000ms setTimeout(() => resolve(this.num * 2), 1000); // (*) } } async function f() { - // waits for 1 second, then result becomes 2 + // venter i 1 sekund, hvorefter resultatet bliver 2 let result = await new Thenable(1); alert(result); } @@ -174,11 +174,11 @@ async function f() { f(); ``` -If `await` gets a non-promise object with `.then`, it calls that method providing the built-in functions `resolve` and `reject` as arguments (just as it does for a regular `Promise` executor). Then `await` waits until one of them is called (in the example above it happens in the line `(*)`) and then proceeds with the result. +Hvis `await` får et ikke-promise object med `.then`, det kalder den metode og giver de indbyggede funktioner `resolve` og `reject` som argumenter (ligesom det gør for en almindelig `Promise` executor). Derefter venter `await` indtil en af dem bliver kaldt (i eksemplet ovenfor sker det i linjen `(*)`) og fortsætter derefter med resultatet. ```` -````smart header="Async class methods" -To declare an async class method, just prepend it with `async`: +````smart header="Async klasse metoder" +For at deklarere en async klasse metode, tilføj `async` før metoden: ```js run class Waiter { @@ -191,38 +191,38 @@ class Waiter { new Waiter() .wait() - .then(alert); // 1 (this is the same as (result => alert(result))) + .then(alert); // 1 (det er det samme som (result => alert(result))) ``` -The meaning is the same: it ensures that the returned value is a promise and enables `await`. +Meningen er den samme: det sikrer at den returnerede værdi er et promise og aktiverer `await`. ```` -## Error handling +## Håndtering af fejl -If a promise resolves normally, then `await promise` returns the result. But in the case of a rejection, it throws the error, just as if there were a `throw` statement at that line. +Hvis et promise løses normalt, så returnerer `await promise` resultatet. Men i tilfældet af en afvisning, kaster det en fejl, som om der var en `throw`-sætning på linjen. -This code: +Denne kode: ```js async function f() { *!* - await Promise.reject(new Error("Whoops!")); + await Promise.reject(new Error("Ups!")); */!* } ``` -...is the same as this: +... er det samme som: ```js async function f() { *!* - throw new Error("Whoops!"); + throw new Error("Ups!"); */!* } ``` -In real situations, the promise may take some time before it rejects. In that case there will be a delay before `await` throws an error. +I virkelige situationer vil et promise tage noget tid før det afvises. I det tilfælde vil der være en forsinkelse før `await` kaster en fejl. -We can catch that error using `try..catch`, the same way as a regular `throw`: +Vi kan opsnappe den fejl ved hjælp af `try..catch`, på samme måde som en almindelig `throw`: ```js run async function f() { @@ -239,7 +239,7 @@ async function f() { f(); ``` -In the case of an error, the control jumps to the `catch` block. We can also wrap multiple lines: +I tilfælde af en fejl, springer kontrollen over til `catch`-blokken. Vi kan også wrappe flere linjer i `try..catch` for at fange fejl i flere `await`: ```js run async function f() { @@ -248,7 +248,7 @@ async function f() { let response = await fetch('/no-user-here'); let user = await response.json(); } catch(err) { - // catches errors both in fetch and response.json + // fanger fejler i både fetch og response.json alert(err); } } @@ -256,33 +256,33 @@ async function f() { f(); ``` -If we don't have `try..catch`, then the promise generated by the call of the async function `f()` becomes rejected. We can append `.catch` to handle it: +Hvis vi ikke har `try..catch`, så vil promise genreret ved kaldet af den asynkrone funktion `f()` blive afvist. Vi kan tilføje `.catch` for at håndtere det: ```js run async function f() { let response = await fetch('http://no-such-url'); } -// f() becomes a rejected promise +// f() bliver et afvist promise *!* -f().catch(alert); // TypeError: failed to fetch // (*) +f().catch(alert); // TypeError: fejlede ved fetch // (*) */!* ``` -If we forget to add `.catch` there, then we get an unhandled promise error (viewable in the console). We can catch such errors using a global `unhandledrejection` event handler as described in the chapter . +Hvis vi glemmer at tilføje `.catch`, så får vi en ikke-håndteret promise-fejl (synlig i konsollen). Vi kan fange sådanne fejl ved hjælp af en global `unhandledrejection`-begivenhedshåndtering som beskrevet i kapitlet . -```smart header="`async/await` and `promise.then/catch`" -When we use `async/await`, we rarely need `.then`, because `await` handles the waiting for us. And we can use a regular `try..catch` instead of `.catch`. That's usually (but not always) more convenient. +```smart header="`async/await` og `promise.then/catch`" +Når vi bruger `async/await`, bruger vi sjældent `.then`, fordi `await` håndterer ventningen for os. Og vi kan bruge en almindelig `try..catch` i stedet for `.catch`. Det er ofte (men ikke altid) mere praktisk. -But at the top level of the code, when we're outside any `async` function, we're syntactically unable to use `await`, so it's a normal practice to add `.then/catch` to handle the final result or falling-through error, like in the line `(*)` of the example above. +Men på den øverste niveau af koden, når vi er uden for enhver `async` funktion, er vi syntaktisk ude af stand til at bruge `await`, så det er en normal praksis at tilføje `.then/catch` for at håndtere det endelige resultat eller fejlen, som i linjen `(*)` i eksemplet ovenfor. ``` -````smart header="`async/await` works well with `Promise.all`" -When we need to wait for multiple promises, we can wrap them in `Promise.all` and then `await`: +````smart header="`async/await` virker godt med `Promise.all`" +Når vi har brug for at vente på flere promises, kan vi pakke dem ind i `Promise.all` og derefter `await`: ```js -// wait for the array of results +// vent på arrayet af resultater let results = await Promise.all([ fetch(url1), fetch(url2), @@ -290,22 +290,22 @@ let results = await Promise.all([ ]); ``` -In the case of an error, it propagates as usual, from the failed promise to `Promise.all`, and then becomes an exception that we can catch using `try..catch` around the call. +I tilfælde af en fejl, propagerer den som sædvanligt, fra det mislykkede promise til `Promise.all`, og så bliver det til en exception, som vi kan fange ved hjælp af `try..catch` omkring kaldet. ```` -## Summary +## Opsummering -The `async` keyword before a function has two effects: +Nøgleordet `async` før en funktion har to effekter: -1. Makes it always return a promise. -2. Allows `await` to be used in it. +1. Gør det til en funktion, der altid returnerer et promise. +2. Tillader `await` at blive brugt i den. -The `await` keyword before a promise makes JavaScript wait until that promise settles, and then: +Nøgleordet `await` før et promise gør JavaScript til at vente indtil det promise løses, og derefter: -1. If it's an error, an exception is generated — same as if `throw error` were called at that very place. -2. Otherwise, it returns the result. +1. Hvis det er en fejl, genereres en exception — samme som hvis `throw error` blev kaldt på det sted. +2. Ellers returnerer det resultatet. -Together they provide a great framework to write asynchronous code that is easy to both read and write. +Sammen udgør de en fremragende framework til at skrive asynkron kode, som er let at læse og skrive. -With `async/await` we rarely need to write `promise.then/catch`, but we still shouldn't forget that they are based on promises, because sometimes (e.g. in the outermost scope) we have to use these methods. Also `Promise.all` is nice when we are waiting for many tasks simultaneously. +Med `async/await` behøver vi sjældent at skrive `promise.then/catch`, men vi bør stadig ikke glemme, at de er baseret på promises, fordi nogle gange (f.eks. i den yderste scope) er vi nødt til at bruge dem. Derudover er `Promise.all` ret smart når vi venter på mange opgaver samtidigt.