Episode 1 — Fundamentals / 1.19 — Conditionals and Loops
1.19.d -- While and Do-While Loops
In one sentence:
whilechecks its condition before each iteration (zero-or-more runs),do...whilechecks after (guaranteeing at least one run) -- both are ideal when the number of iterations is unknown in advance.
Navigation: <-- 1.19.c -- For Loop . 1.19.e -- Break and Continue -->
1. The while loop
while (condition) {
// body -- runs as long as condition is truthy
}
Execution flow:
- Evaluate
condition. - If truthy -- run the body, then go back to step 1.
- If falsy -- skip the body, loop ends.
let count = 0;
while (count < 5) {
console.log(count);
count++;
}
// Output: 0, 1, 2, 3, 4
If the condition is false from the start, the body never runs:
let x = 10;
while (x < 5) {
console.log(x); // never executes
x++;
}
2. The do...while loop
do {
// body -- always runs at least once
} while (condition);
Execution flow:
- Run the body first.
- Evaluate
condition. - If truthy -- go back to step 1.
- If falsy -- loop ends.
let count = 0;
do {
console.log(count);
count++;
} while (count < 5);
// Output: 0, 1, 2, 3, 4
The key difference: the body runs at least once, even if the condition is false:
let x = 10;
do {
console.log(x); // prints 10 -- runs once
x++;
} while (x < 5);
// Output: 10
3. Side-by-side comparison
| Feature | while | do...while |
|---|---|---|
| Condition check | Before each iteration | After each iteration |
| Minimum executions | 0 (body may never run) | 1 (body always runs once) |
| Semicolon | No semicolon needed after } | Requires ; after while(condition); |
| Use case | Default choice when iterations unknown | When you need at least one pass |
4. When to use while vs for
| Scenario | Preferred loop | Why |
|---|---|---|
| Known iteration count | for | The three-part header makes count logic clear |
| Unknown iteration count | while | No need for an artificial counter |
| Iterating an array by index | for or for...of | Index logic belongs in the header |
| Reading until a condition changes | while | No meaningful init/update for the header |
| Processing a queue/stack | while | Pop until empty |
// for is clearer when you know the count
for (let i = 0; i < 10; i++) { ... }
// while is clearer when count is unknown
while (queue.length > 0) {
const item = queue.shift();
process(item);
}
5. Infinite loops -- causes and how to avoid
An infinite loop runs forever because its condition never becomes falsy.
Common causes
// 1. Forgetting to update the loop variable
let i = 0;
while (i < 10) {
console.log(i);
// BUG: i is never incremented -- loops forever
}
// 2. Updating in the wrong direction
let j = 10;
while (j > 0) {
console.log(j);
j++; // BUG: j goes UP, never < 0
}
// 3. Condition that can never be false
while (true) {
// intentional only if there's a break/return inside
}
// 4. Off-by-one in condition
let k = 0;
while (k !== 10) {
console.log(k);
k += 3; // k goes 0, 3, 6, 9, 12, 15... never exactly 10
}
How to avoid infinite loops
- Always modify the variable that the condition depends on.
- Use
<or<=instead of!==when incrementing by a step size -- it will eventually exit even if you skip the exact value. - Add a safety counter during development:
let iterations = 0;
const MAX = 10000;
while (someCondition) {
if (iterations++ > MAX) {
console.error("Safety limit reached -- possible infinite loop");
break;
}
// ... loop body
}
6. Sentinel-controlled loops
A sentinel is a special value that signals "stop." The loop does not know in advance how many iterations it will need -- it keeps going until it encounters the sentinel.
Example: Processing until a marker
const data = [10, 25, 33, 47, -1, 88, 99]; // -1 is the sentinel
let index = 0;
let sum = 0;
while (data[index] !== -1) {
sum += data[index];
index++;
}
console.log(`Sum of values before sentinel: ${sum}`); // 115
console.log(`Processed ${index} items`); // 4
Example: Collatz conjecture (stop when reaching 1)
function collatzSteps(n) {
let steps = 0;
while (n !== 1) {
if (n % 2 === 0) {
n = n / 2;
} else {
n = 3 * n + 1;
}
steps++;
}
return steps;
}
console.log(collatzSteps(6)); // 8 steps: 6->3->10->5->16->8->4->2->1
console.log(collatzSteps(27)); // 111 steps
7. Real-world examples
Example 1 -- User input validation loop
In a do...while, the prompt runs at least once, then repeats if input is invalid.
// Browser environment (conceptual -- prompt() blocks)
let userInput;
do {
userInput = prompt("Enter a number between 1 and 10:");
} while (isNaN(userInput) || userInput < 1 || userInput > 10);
console.log(`You entered: ${userInput}`);
This pattern naturally fits do...while because you must ask at least once before you can validate.
Example 2 -- Game loop concept
let gameRunning = true;
let round = 0;
while (gameRunning) {
round++;
console.log(`--- Round ${round} ---`);
const playerHP = getPlayerHP();
const enemyHP = getEnemyHP();
if (playerHP <= 0) {
console.log("Game Over. You lost.");
gameRunning = false;
} else if (enemyHP <= 0) {
console.log("Victory! You won!");
gameRunning = false;
} else {
executeTurn();
}
}
Example 3 -- Reading a linked list
function printList(head) {
let current = head;
while (current !== null) {
console.log(current.value);
current = current.next;
}
}
// Given: { value: 1, next: { value: 2, next: { value: 3, next: null } } }
// Output: 1, 2, 3
Example 4 -- Exponential backoff retry
async function fetchWithRetry(url, maxRetries = 5) {
let attempt = 0;
let delay = 1000; // start at 1 second
while (attempt < maxRetries) {
try {
const response = await fetch(url);
if (response.ok) return await response.json();
throw new Error(`HTTP ${response.status}`);
} catch (err) {
attempt++;
console.log(`Attempt ${attempt} failed. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
delay *= 2; // exponential backoff
}
}
throw new Error(`Failed after ${maxRetries} attempts`);
}
Example 5 -- Binary search with while
function binarySearch(sortedArr, target) {
let low = 0;
let high = sortedArr.length - 1;
while (low <= high) {
const mid = Math.floor((low + high) / 2);
if (sortedArr[mid] === target) {
return mid; // found
} else if (sortedArr[mid] < target) {
low = mid + 1; // search right half
} else {
high = mid - 1; // search left half
}
}
return -1; // not found
}
console.log(binarySearch([1, 3, 5, 7, 9, 11], 7)); // 3
console.log(binarySearch([1, 3, 5, 7, 9, 11], 6)); // -1
8. Converting between for and while
Any for loop can be rewritten as a while loop and vice versa:
// for version
for (let i = 0; i < 5; i++) {
console.log(i);
}
// equivalent while version
let i = 0;
while (i < 5) {
console.log(i);
i++;
}
The for loop is preferred when all three parts (init, condition, update) are simple and related to the same counter. The while loop is preferred when the logic is more complex or the termination condition is not count-based.
9. Common mistakes
| Mistake | What happens | Fix |
|---|---|---|
| Forgetting to update loop variable | Infinite loop | Ensure the variable in the condition changes each iteration |
| Off-by-one in condition | One too many or too few iterations | Trace the loop on paper for first and last iterations |
| Modifying array while iterating | Skipped or duplicated elements | Iterate backward or copy the array first |
Using do...while when zero iterations are valid | Unexpected first execution | Use while instead |
Missing semicolon after do...while | Syntax error | do { ... } while (cond); -- semicolon required |
Key takeaways
whilechecks the condition first -- the body may run zero times.do...whileruns the body first, then checks -- guarantees at least one execution.- Use
whilewhen the number of iterations is unknown in advance. - Use
do...whilewhen you need at least one pass (e.g., input validation, menu display). - Always ensure the loop progresses toward termination -- update the variable the condition depends on.
Explain-It Challenge
Explain without notes:
- What is the one behavioral difference between
whileanddo...while? - Give a scenario where
do...whileis the natural choice overwhile. - A loop uses
while (x !== 10)and incrementsxby 3 starting from 0. Will it ever terminate? Why or why not?
Navigation: <-- 1.19.c -- For Loop . 1.19.e -- Break and Continue -->