JavaScript Continue Statement: Skipping Iterations

Learn how the JavaScript continue statement skips iterations in loops. Covers continue in for loops, while loops, for...of, labeled continue for nested loops, and practical filtering patterns.

JavaScriptbeginner
9 min read

The break statement exits a loop entirely. But sometimes you do not want to stop the loop. You want to skip one iteration and keep going with the next. Maybe the current item is invalid data that should not be processed. Maybe certain indices need special handling elsewhere. Maybe the current element does not match the criteria you care about.

The continue statement skips the rest of the current iteration and jumps to the next one. The loop keeps running; only the current cycle is skipped. This tutorial covers how continue behaves in every loop type, practical patterns for data filtering and validation, the critical difference in while loops versus for loops, labeled continue for nested loops, and when to use continue versus alternative approaches.

How Continue Works

The continue statement skips the remaining code in the current iteration:

javascriptjavascript
for (let i = 0; i < 6; i++) {
  if (i === 3) {
    continue; // skip iteration when i is 3
  }
  console.log(i);
}
// Output: 0, 1, 2, 4, 5
// (3 is skipped, but the loop continues)

Execution flow for i = 3:

  1. i === 3 is true
  2. continue fires
  3. The console.log(i) below is skipped
  4. Execution jumps to i++ (the update expression)
  5. Loop continues with i = 4
BehaviorDetails
SkipsRest of the current iteration's body
Continues toNext iteration (update expression in for loops, condition check in while)
Loop survivesYes, the loop keeps running
Works infor, for...of, for...in, while, do...while
Does NOT work in.forEach(), .map(), or other array method callbacks

Continue in For Loops

In a standard for loop, continue jumps to the update expression (i++), not back to the condition:

javascriptjavascript
for (let i = 0; i < 5; i++) {
  // 1. Condition check: i < 5
  if (i % 2 === 0) {
    continue; // 2. Skips to step 4 (i++)
  }
  console.log(i); // 3. Only runs for odd numbers
  // 4. Update: i++ (continue jumps here)
}
// Output: 1, 3

This is safe because the counter always increments, preventing infinite loops.

Filtering Odd Numbers

javascriptjavascript
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evens = [];
 
for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] % 2 !== 0) {
    continue; // skip odd numbers
  }
  evens.push(numbers[i]);
}
 
console.log(evens); // [2, 4, 6, 8, 10]

Skipping Invalid Data

javascriptjavascript
const rawData = ["42", "hello", "17", "", "99", null, "5"];
const validNumbers = [];
 
for (const item of rawData) {
  if (item === null || item === "") continue;
 
  const num = parseInt(item, 10);
  if (isNaN(num)) continue;
 
  validNumbers.push(num);
}
 
console.log(validNumbers); // [42, 17, 99, 5]

Continue in While Loops: The Danger Zone

In a while loop, continue jumps to the condition check, not to an update expression. This means the counter update can be skipped:

javascriptjavascript
// BUG: infinite loop!
let i = 0;
while (i < 10) {
  if (i === 5) {
    continue; // jumps to condition check, i stays at 5 forever
  }
  console.log(i);
  i++;
}
 
// FIX: increment BEFORE the continue
let i = 0;
while (i < 10) {
  if (i === 5) {
    i++; // increment first
    continue;
  }
  console.log(i);
  i++;
}
// Output: 0, 1, 2, 3, 4, 6, 7, 8, 9
Always Increment Before Continue in While Loops

In a for loop, continue safely jumps to the update expression. In a while loop, continue jumps directly to the condition check, bypassing any counter update at the bottom of the body. Always place the counter increment before any continue statement in while loops, or restructure the loop so the increment cannot be skipped.

Safe Pattern: Increment at the Top

javascriptjavascript
let i = -1; // start one before the first value
while (i < 9) {
  i++; // always runs, even after continue
 
  if (i === 5) continue;
 
  console.log(i);
}
// Output: 0, 1, 2, 3, 4, 6, 7, 8, 9

Continue in For...Of Loops

continue works cleanly in for...of because there is no manual counter to manage:

javascriptjavascript
const tasks = [
  { name: "Deploy", status: "done" },
  { name: "Test", status: "pending" },
  { name: "Review", status: "done" },
  { name: "Build", status: "pending" },
];
 
for (const task of tasks) {
  if (task.status === "done") continue; // skip completed tasks
 
  console.log(`TODO: ${task.name}`);
}
// TODO: Test
// TODO: Build

Continue in Do-While Loops

In a do-while loop, continue jumps to the condition check at the bottom:

javascriptjavascript
let i = 0;
 
do {
  i++;
  if (i % 3 === 0) continue; // skip multiples of 3
  console.log(i);
} while (i < 10);
// Output: 1, 2, 4, 5, 7, 8, 10

Since the increment is before the continue, this is safe from infinite loops.

Labeled Continue: Skipping in Nested Loops

Like labeled break, labeled continue lets you skip iterations of an outer loop from inside an inner loop:

javascriptjavascript
const students = [
  { name: "Alice", grades: [85, 92, 78] },
  { name: "Bob", grades: [45, 92, 88] },
  { name: "Carol", grades: [90, 95, 88] },
];
 
studentLoop:
for (const student of students) {
  for (const grade of student.grades) {
    if (grade < 50) {
      console.log(`${student.name} has a failing grade (${grade}), skipping`);
      continue studentLoop; // skip to the next student
    }
  }
  console.log(`${student.name}: all grades passing`);
}
// Alice: all grades passing
// Bob has a failing grade (45), skipping
// Carol: all grades passing

Without the label, continue would only skip the current grade in the inner loop, not the entire student.

Processing a Grid with Row-Level Skipping

javascriptjavascript
const grid = [
  [1, 0, 3],
  [4, 5, 6],
  [0, 8, 9],
];
 
rowLoop:
for (let row = 0; row < grid.length; row++) {
  for (let col = 0; col < grid[row].length; col++) {
    if (grid[row][col] === 0) {
      console.log(`Row ${row} contains zero, skipping entire row`);
      continue rowLoop; // skip to next row
    }
  }
  console.log(`Row ${row} is clean: [${grid[row]}]`);
}
// Row 0 contains zero, skipping entire row
// Row 1 is clean: [4,5,6]
// Row 2 contains zero, skipping entire row

Continue vs Guard Clauses

A continue statement at the top of a loop body acts like a guard clause in a function. Both approaches are valid; choose based on readability:

javascriptjavascript
// Approach 1: continue as guard clause (flat structure)
for (const user of users) {
  if (!user.active) continue;
  if (!user.email) continue;
  if (user.role === "bot") continue;
 
  sendNewsletter(user);
}
 
// Approach 2: nested if (deeper structure)
for (const user of users) {
  if (user.active && user.email && user.role !== "bot") {
    sendNewsletter(user);
  }
}
ApproachProsCons
Continue guardsFlat code, easy to add conditionsMultiple early exits to track
Nested ifSingle clear condition blockDeep nesting with many conditions
Continue Guards for Complex Filtering

When you have three or more conditions to check, continue guards keep the code flat and each condition on its own line. This is easier to read and modify than a deeply nested if statement with multiple && operators.

Continue Does NOT Work in forEach

Just like break, continue is a syntax error inside .forEach():

javascriptjavascript
// SYNTAX ERROR
[1, 2, 3].forEach((num) => {
  if (num === 2) continue; // SyntaxError
  console.log(num);
});
 
// Workaround: use return (acts like continue for the callback)
[1, 2, 3].forEach((num) => {
  if (num === 2) return; // skips this callback invocation
  console.log(num);
});
// Output: 1, 3
 
// Better: use for...of with real continue
for (const num of [1, 2, 3]) {
  if (num === 2) continue;
  console.log(num);
}

Practical Patterns

Processing CSV rows with Validation

javascriptjavascript
const csvRows = [
  "name,age,email",       // header
  "Alice,28,alice@example.com",
  "",                       // empty row
  "Bob,,bob@example.com",  // missing age
  "Carol,35,carol@example.com",
];
 
const validRecords = [];
 
for (let i = 0; i < csvRows.length; i++) {
  if (i === 0) continue; // skip header row
 
  const row = csvRows[i].trim();
  if (!row) continue; // skip empty rows
 
  const [name, age, email] = row.split(",");
  if (!name || !age || !email) continue; // skip incomplete rows
 
  validRecords.push({ name, age: parseInt(age, 10), email });
}
 
console.log(validRecords);
// [{ name: "Alice", age: 28, email: "alice@example.com" },
//  { name: "Carol", age: 35, email: "carol@example.com" }]

Accumulating with Exceptions

javascriptjavascript
const transactions = [
  { amount: 100, type: "credit" },
  { amount: -50, type: "debit" },
  { amount: 0, type: "hold" },
  { amount: 200, type: "credit" },
  { amount: -30, type: "debit" },
];
 
let totalCredits = 0;
 
for (const tx of transactions) {
  if (tx.type !== "credit") continue;
  totalCredits += tx.amount;
}
 
console.log(`Total credits: $${totalCredits}`); // Total credits: $300

Batch Processing with Rate Limits

javascriptjavascript
const items = getItemsToProcess();
let processed = 0;
 
for (const item of items) {
  if (item.status === "completed") continue; // already done
  if (item.locked) continue; // another process owns it
 
  await processItem(item);
  processed++;
 
  if (processed >= 50) break; // batch limit
}

Break vs Continue Comparison

javascriptjavascript
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 
// continue: skip even numbers, keep looping
for (const n of numbers) {
  if (n % 2 === 0) continue;
  console.log(n);
}
// 1, 3, 5, 7, 9 (all odd numbers printed)
 
// break: stop at the first even number
for (const n of numbers) {
  if (n % 2 === 0) break;
  console.log(n);
}
// 1 (only first number, then 2 triggers break)
Featurebreakcontinue
EffectExits the entire loopSkips current iteration only
Remaining iterationsAll skippedLoop continues normally
Use caseFound result, error, or limit reachedCurrent item is invalid or irrelevant
While loop riskNoneCan cause infinite loop if counter is skipped

Best Practices

Place continue guards at the top of the loop body. Early continues act as guard clauses, keeping the main logic unindented and easy to read. Avoid continue statements buried in the middle of complex logic.

Always increment before continue in while loops. In for loops, continue safely jumps to the update expression. In while loops, it jumps to the condition, so any counter update after the continue is skipped. Put the increment before the continue or at the very top of the body.

Prefer for...of when using continue. The for...of loop has no manual counter to manage, eliminating the risk of infinite loops from skipped updates.

Use continue for filtering, not complex logic branching. Continue works best for simple "skip this one" decisions. If the skip logic requires multiple steps or side effects, extract it into a function.

Limit to one or two continue conditions per loop. More than two or three continue guards at the top of a loop can be hard to track. If the filtering logic is complex, consider using .filter() before the loop to separate concerns.

Rune AI

Rune AI

Key Insights

  • Continue skips one iteration, not the whole loop: the loop keeps running with the next item
  • Safe in for loops: continue jumps to the update expression, so the counter always increments
  • Dangerous in while loops: counter updates after continue are skipped, risking infinite loops
  • Use as guard clauses: place continue checks at the top of the loop body to keep main logic flat
  • Does not work in forEach: use return inside callbacks or switch to for...of for proper continue support
RunePowered by Rune AI

Frequently Asked Questions

What is the difference between continue and break?

`continue` skips the rest of the current iteration and moves to the next one. The loop keeps running. `break` exits the entire loop immediately. No more iterations execute. Use `continue` when you want to skip certain items but process the rest. Use `break` when you want to stop the loop entirely.

Does continue skip the update expression in a for loop?

No. In a `for` loop, `continue` jumps to the update expression (like `i++`), which still runs. Then the condition is checked. The counter always increments correctly. This is different from while loops, where `continue` jumps directly to the condition check, potentially skipping counter updates at the bottom of the body.

Can I use continue in a forEach loop?

`continue` is a syntax error inside `.forEach()` because the callback is a function, not a loop body. You can use `return` inside the callback to achieve a similar effect: `return` exits the current callback invocation but does not stop `.forEach()` from calling the callback for the next element. For full `continue` and `break` support, use `for...of` instead.

Can continue cause an infinite loop?

Yes, in while and do-while loops. If the counter increment is placed after the `continue` statement on the same level, it gets skipped whenever `continue` fires. The counter never changes, and the condition never becomes false. This cannot happen in for loops because the update expression runs even after a `continue`.

When should I use continue versus filter?

Use `continue` inside a `for` loop when you need side effects during iteration (like logging, API calls, or accumulating results) and want to skip certain items inline. Use `.filter()` before the loop when you want to cleanly separate the filtering step from the processing step. If you do not need the loop index or break capability, `.filter()` followed by `.forEach()` or `.map()` is often clearer.

Conclusion

The continue statement skips the current iteration and moves to the next one, keeping the loop alive. It is most useful as a guard clause at the top of a loop body, filtering out invalid or irrelevant items before the main processing logic. The critical safety rule is to always place counter updates before continue in while loops, since continue jumps directly to the condition check and can bypass updates. For cleanest behavior, use for...of loops where there is no manual counter to manage.