Episode 1 — Fundamentals / 1.19 — Conditionals and Loops

1.19.d -- While and Do-While Loops

In one sentence: while checks its condition before each iteration (zero-or-more runs), do...while checks 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:

  1. Evaluate condition.
  2. If truthy -- run the body, then go back to step 1.
  3. 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:

  1. Run the body first.
  2. Evaluate condition.
  3. If truthy -- go back to step 1.
  4. 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

Featurewhiledo...while
Condition checkBefore each iterationAfter each iteration
Minimum executions0 (body may never run)1 (body always runs once)
SemicolonNo semicolon needed after }Requires ; after while(condition);
Use caseDefault choice when iterations unknownWhen you need at least one pass

4. When to use while vs for

ScenarioPreferred loopWhy
Known iteration countforThe three-part header makes count logic clear
Unknown iteration countwhileNo need for an artificial counter
Iterating an array by indexfor or for...ofIndex logic belongs in the header
Reading until a condition changeswhileNo meaningful init/update for the header
Processing a queue/stackwhilePop 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

  1. Always modify the variable that the condition depends on.
  2. Use < or <= instead of !== when incrementing by a step size -- it will eventually exit even if you skip the exact value.
  3. 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

MistakeWhat happensFix
Forgetting to update loop variableInfinite loopEnsure the variable in the condition changes each iteration
Off-by-one in conditionOne too many or too few iterationsTrace the loop on paper for first and last iterations
Modifying array while iteratingSkipped or duplicated elementsIterate backward or copy the array first
Using do...while when zero iterations are validUnexpected first executionUse while instead
Missing semicolon after do...whileSyntax errordo { ... } while (cond); -- semicolon required

Key takeaways

  1. while checks the condition first -- the body may run zero times.
  2. do...while runs the body first, then checks -- guarantees at least one execution.
  3. Use while when the number of iterations is unknown in advance.
  4. Use do...while when you need at least one pass (e.g., input validation, menu display).
  5. Always ensure the loop progresses toward termination -- update the variable the condition depends on.

Explain-It Challenge

Explain without notes:

  1. What is the one behavioral difference between while and do...while?
  2. Give a scenario where do...while is the natural choice over while.
  3. A loop uses while (x !== 10) and increments x by 3 starting from 0. Will it ever terminate? Why or why not?

Navigation: <-- 1.19.c -- For Loop . 1.19.e -- Break and Continue -->