This commit is contained in:
Philippe Torrel
2026-11-02 11:17:53 +01:00
parent 7936f3387b
commit c936a7f00c
12 changed files with 648 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
{
const firstName = 'John';
// if (firstName === John) {
// // ReferenceError: John is not defined
// console.log(firstName);
// }
// if (firstname === 'John') {
// // Uncaught ReferenceError: firstname is not defined
// console.log(firstName);
// }
if (firstName === 'John') {
console.log(firstName);
}
function greet() {
console.log('Hello, ' + fullName); // Cannot find name 'fullName'.
console.log(typeof fullName);
}
// greet(); // => ReferenceError: fullName is not defined
// function greet(fullName) {
// console.log(`Hello, ${fullName}`);
// }
greet('John Wick');
}
@@ -0,0 +1,65 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Nesting if-statements</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<main>
<div class="container py-5">
<h1>Nesting if-statements</h1>
</div>
</main>
<script>
'use strict';
let isSystemUpgrading = false;
let isLoggedIn = true;
let hasAdminRights = true;
const items = [
{
name: 'Item A',
cost: 150,
},
{
name: 'Item B',
cost: 250,
},
{
name: 'Item C',
cost: 350,
},
];
function processRequests() {
if (!isSystemUpgrading) {
if (isLoggedIn) {
if (hasAdminRights) {
items.forEach((item) => {
console.log(`Item Name: ${item.name}`);
if (item.cost > 200) {
console.log('Item cost is greater than 200.');
} else {
console.log('Item cost is less than or equal to 200.');
}
});
} else {
console.log('You do not have administrative privileges.');
}
} else {
console.log('You must be logged in to view items.');
}
} else {
console.log('System is currently being upgraded.');
}
}
console.time('without inversion');
processRequests();
console.timeEnd('without inversion');
</script>
</body>
</html>
@@ -0,0 +1,68 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Nesting if-statements vermeiden über inversion</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<main>
<div class="container py-5">
<h1>Nesting if-statements vermeiden über <strong>inversion</strong></h1>
</div>
</main>
<script>
'use strict';
const isSystemUpgrading = true;
const isLoggedIn = true;
const hasAdminRights = true;
const items = [
{
name: 'Item A',
cost: 150,
},
{
name: 'Item B',
cost: 250,
},
{
name: 'Item C',
cost: 350,
},
];
function processRequests() {
if (isSystemUpgrading) {
console.log('System is currently being upgraded.');
return;
}
if (!isLoggedIn) {
console.log('You must be logged in to view items.');
return;
}
if (!hasAdminRights) {
console.log('You do not have administrative privileges.');
return;
}
items.forEach((item) => {
console.log(`Item Name: ${item.name}`);
if (item.cost > 200) {
console.log('Item cost is greater than 200.');
} else {
console.log('Item cost is less than or equal to 200.');
}
});
}
console.time('inversion');
processRequests();
console.timeEnd('inversion');
</script>
</body>
</html>
@@ -0,0 +1,57 @@
'use strict';
const isSystemUpgrading = false;
const isLoggedIn = true;
const hasAdminRights = true;
const items = [
{ name: 'Item A', cost: 150 },
{ name: 'Item B', cost: 250 },
{ name: 'Item C', cost: 350 },
];
function runNested() {
let counter = 0;
if (!isSystemUpgrading) {
if (isLoggedIn) {
if (hasAdminRights) {
for (let i = 0; i < items.length; i++) {
if (items[i].cost > 200) counter++;
}
}
}
}
return counter;
}
function runGuard() {
let counter = 0;
if (isSystemUpgrading) return counter;
if (!isLoggedIn) return counter;
if (!hasAdminRights) return counter;
for (let i = 0; i < items.length; i++) {
if (items[i].cost > 200) counter++;
}
return counter;
}
const ITERATIONS = 10_000_000;
// Warmup
for (let i = 0; i < 100_000; i++) {
runNested();
runGuard();
}
console.time('Verschachtelt');
for (let i = 0; i < ITERATIONS; i++) runNested();
console.timeEnd('Verschachtelt');
console.time('Early Returns');
for (let i = 0; i < ITERATIONS; i++) runGuard();
console.timeEnd('Early Returns');
// In diesem Test laufen beide Varianten im Chrome V8-Engine praktisch gleich schnell (innerhalb normaler CPU-Schwankungen).
// Fazit: Verwende Early Returns (Guard Clauses). Sie bieten zwar keinen nennenswerten Performance-Vorsprung gegenüber verschachtelten Abfragen, reduzieren aber die zyklomatische Komplexität und machen den Code deutlich lesbarer.
@@ -0,0 +1,38 @@
## Kein Performanceunterschied bei Inversion
### 1. AST-Normalisierung & SSA (Control Flow Graphs)
V8 (über den Turbofan-Optimierungs-Compiler) führt deinen Code nicht zeilenweise so aus, wie du ihn schreibst:
* **Control Flow Graph (CFG):** V8 wandelt sowohl verschachtelte Blöcke als auch Early Returns in dieselbe abstrakte Repräsentation um (Static Single Assignment / SSA Form).
* **Pfad-Reduktion:** Ein verschachtelter Baum `if (A) { if (B) { if (C) { ... } } }` wird im Zwischencode auf denselben Entscheidungspfad reduziert wie `if (!A) return; if (!B) return; if (!C) return;`.
* **Identischer Maschinencode:** Sobald Turbofan den Code optimiert, erzeugen beide Varianten exakt dieselbe Sequenz aus bedingten Sprungbefehlen (`test`, `jnz` / `jz`) auf Assemblerebene.
---
### 2. Hardware-Ebene: CPU Branch Prediction
Unabhängig von der JS-Engine entscheidet die Hardware über die Geschwindigkeit von Verzweigungen:
* Wenn Bedingungen wie `isLoggedIn` stabil sind (z. B. immer `true`), lernt der **Branch Predictor** der CPU das Muster nach wenigen Durchläufen.
* Die CPU führt den Zweig spekulativ ohne Pipeline-Stall aus (Branch Prediction Penalty = 0 Takte).
* Ob der nicht genommene Zweig am Ende der Funktion (`nested`) oder direkt hinter dem Check (`early return`) liegt, macht für die Ausführungszeit der CPU keinen Unterschied.
---
### 3. Warum misst man im Firefox (SpiderMonkey) manchmal Unterschiede?
SpiderMonkey (Firefox) und V8 (Chrome) verfolgen unterschiedliche Strategien bei der Bytecode-Erzeugung und den JIT-Stufen:
| Aspekt | Chrome (V8) | Firefox (SpiderMonkey) |
| --- | --- | --- |
| **Pipeline** | Ignition (Interpreter) $\rightarrow$ Sparkplug $\rightarrow$ Maglev $\rightarrow$ Turbofan | C++ Interpreter $\rightarrow$ Baseline Interpreter $\rightarrow$ Baseline Compiler $\rightarrow$ WarpMonkey |
| **Bytecode-Layout** | V8 optimiert Jump-Targets früh im Bytecode-Generator; Basic Blocks werden linear angeordnet. | SpiderMonkey behält in frühen Phasen oft ein Bytecode-Layout bei, das näher an der Quellcode-Struktur liegt. |
| **Bailout / OSR** | Sehr aggressives Inlining und Dead-Code-Elimination im `Maglev`/`Turbofan`-Layer. | `WarpMonkey` nutzt Transpilation über CacheIR; je nach Verschachtelungstiefe können Scope- und Frame-Handling im Baseline-Tier minimal variieren. |
In **nicht-hochoptimiertem Code** (z. B. Skripte, die nur wenige Male laufen und im Interpreter bzw. Baseline JIT verbleiben):
* Verursacht tiefe Verschachtelung in manchen Engines zusätzlichen Overhead beim Verwalten von Lexical Environments/Scopes auf dem Stack.
* Early Returns erlauben es dem Interpreter, den aktuellen Stack-Frame schneller abzubauen, ohne tiefer liegende Scope-Hierarchien zu durchlaufen.
Sobald der Code jedoch "heiß" läuft (nach einigen tausend Iterationen), eliminieren sowohl Turbofan als auch WarpMonkey diesen Unterschied vollständig.
@@ -0,0 +1,61 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Nested if-statements</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<main>
<div class="container py-5">
<h1>Nested if-statements</h1>
</div>
</main>
<script>
'use strict';
const isSystemUpgrading = false;
const isLoggedIn = true;
const hasAdminRights = true;
const items = [
{
name: 'Item A',
cost: 150,
},
{
name: 'Item B',
cost: 250,
},
{
name: 'Item C',
cost: 350,
},
];
function processRequests() {
if (isSystemUpgrading) {
console.log('System is currently being upgraded.');
return;
}
if (!isLoggedIn || !hasAdminRights) {
console.log('You must be logged in and have administrative privileges to view items.');
return;
}
items.forEach((item) => {
console.log(`Item Name: ${item.name}`);
if (item.cost > 200) {
console.log('Item cost is greater than 200.');
} else {
console.log('Item cost is less than or equal to 200.');
}
});
}
processRequests();
</script>
</body>
</html>
@@ -0,0 +1,79 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Extraction</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<main>
<div class="container py-5">
<h1>Extraction</h1>
</div>
</main>
<script>
'use strict';
const isSystemUpgrading = false;
const isLoggedIn = true;
const hasAdminRights = true;
const items = [
{
name: 'Item A',
cost: 150,
},
{
name: 'Item B',
cost: 250,
},
{
name: 'Item C',
cost: 350,
},
];
// Extraction
function displayItemDetails(item) {
console.log(`Item Name: ${item.name}`);
if (item.cost > 200) {
console.log('Item cost is greater than 200.');
} else {
console.log('Item cost is less than or equal to 200.');
}
}
// auslagerung in utils/helper Ordner möglich
function hasAccessRights() {
// if (isLoggedIn && hasAdminRights) {
// return true
// } else {
// return false
// }
// return (isLoggedIn && hasAdminRights) ? true : false;
return isLoggedIn && hasAdminRights;
}
function processRequests() {
// Guard (early returns bzw. inversion)
if (isSystemUpgrading) {
console.log('System is currently being upgraded.');
return;
}
// Extraction
if (!hasAccessRights()) {
console.log('You must be logged in and have administrative privileges to view items.');
return;
}
items.forEach(displayItemDetails); // Funktionsreferenz
}
processRequests();
</script>
</body>
</html>
@@ -0,0 +1,41 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DRY - Don't Repeat Yourself</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<main>
<div class="container py-5">
<h1>DRY - Don't Repeat Yourself</h1>
</div>
</main>
<script>
'use strict';
function calculateRectangles() {
// Rectangle 1
const length1 = 15;
const width1 = 10;
const area1 = length1 * width1;
console.log('Area of Rectangle 1:', area1);
// Rectangle 2
const length2 = 12;
const width2 = 8;
const area2 = length2 * width2;
console.log('Area of Rectangle 2:', area2);
// Rectangle 3
const length3 = 10;
const width3 = 5;
const area3 = length3 * width3;
console.log('Area of Rectangle 3:', area3);
}
calculateRectangles();
</script>
</body>
</html>
@@ -0,0 +1,96 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DRY - Don't Repeat Yourself - Regel anwenden</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<main>
<div class="container py-5">
<h1>DRY - Don't Repeat Yourself - Regel anwenden</h1>
<div class="output alert alert-secondary my-3"></div>
</div>
</main>
<script>
'use strict';
// IIFE - Immediately invoked function expression. - sorgt für eingeschränkten Gültigkeitsbereich (Schutz) vom Code
(() => {
// === DOM & VARS =======
const DOM = {
output: document.querySelector('.output'),
};
const rectangles = [
{ length: 15, width: 10 },
{ length: 12, width: 8 },
{ length: 10, width: 5 },
];
const rectangle = { length: 10, width: 12 };
// === INIT =============
// Newspaper-Metapher Prinzip
const init = () => {
const areas = calcRectangles(rectangles);
let html = '';
areas.forEach((area, idx) => {
html += `Area of Rectange ${idx + 1}: ${area}<br />`;
});
DOM.output.innerHTML = html;
};
// === EVENTHANDLER =====
// === XHR/FETCH ========
// === FUNCTIONS ========
const calcRectangles = (rects = []) => {
rects = Array.isArray(rects) ? rects : [rects];
const areas = rects.map((rect) => rect.length * rect.width);
return areas;
};
init();
})();
</script>
</body>
</html>
<!--
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DRY - Don't Repeat Yourself</title>
</head>
<body>
<h1>DRY - Don't Repeat Yourself</h1>
<script>
'use strict';
function calculateRectangles() {
const rectangles = [
{ length: 15, width: 10 },
{ length: 12, width: 8 },
{ length: 10, width: 5 },
];
rectangles.forEach((rect, index) => {
const area = rect.length * rect.width;
console.log(`Area of Rectangle ${index + 1}:`, area);
});
}
calculateRectangles();
</script>
</body>
</html> -->
@@ -0,0 +1,63 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Syntax Error</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<main>
<div class="container py-5">
<h1>Syntax <code>Error</code></h1>
</div>
</main>
<script>
'use strict';
{
const age = 25;
// console.log('My age is, age); // Uncaught SyntaxError: Invalid or unexpected token
console.log('My age is, age');
// function addNumbers(num1, num2 {
// return num1 + num2;
// }
// => SyntaxError: Unexpected token '{'
// const addNumbers (num1,num2) => {
// return num1 + num2;
// }
// Uncaught SyntaxError: Missing initializer in const declaration
const addNumbers = (num1, num2) => {
return num1 + num2;
};
console.log(1, 2);
// let person = {
// firstName: 'John'
// lastName: 'Doe',
// }
// => SyntaxError: Unexpected identifier 'lastName'
// let person = {
// firstName: 'John',
// lastName: 'Doe',
// };
// const const = "value"; // => SyntaxError: Unexpected token 'const'
// let class = "Math"; // => SyntaxError: Unexpected token 'class'
// let for = 'for statement' // => SyntaxError: Unexpected token 'for'
// const 🤡 = 'clown' // => SyntaxError: Invalid or unexpected token
// const % = 'arithmetic'; // => SyntaxError: Invalid or unexpected token
// const Math = 'test';
// const isNaN = 'is nicht';
}
</script>
</body>
</html>
@@ -0,0 +1,50 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Reference Error</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<main>
<div class="container py-5">
<h1>Reference Error</h1>
</div>
</main>
<script>
'use strict';
{
const firstName = 'John';
// if (firstName === John) {
// // ReferenceError: John is not defined
// console.log(firstName);
// }
// if (firstname === 'John') {
// // Uncaught ReferenceError: firstname is not defined
// console.log(firstName);
// }
if (firstName === 'John') {
console.log(firstName);
}
function greet() {
console.log('Hello, ' + fullName);
console.log(typeof fullName);
}
// greet(); // => ReferenceError: fullName is not defined
// function greet(fullName) {
// console.log(`Hello, ${fullName}`);
// }
greet('John Wick');
}
</script>
</body>
</html>