Skip to content

js-algorithm-optimizations

<!-- Loaded by performance-optimization-engineer when task involves Set, Map, array, loop, sort, flatMap, early return, or index maps -->

From plugin
vexjoy-agent
413198 skills198 agents10 commands86 hooks
Install
$ npx -y skills add notque/vexjoy-agent --agent claude-code

How it fires

How this agent gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.

Context preview

The summary Claude sees to decide when to auto-load this agent.

<!-- Loaded by performance-optimization-engineer when task involves Set, Map, array, loop, sort, flatMap, early return, or index maps -->

Agent definition

js-algorithm-optimizations.md

JavaScript Algorithm Optimizations Reference

<!-- Loaded by performance-optimization-engineer when task involves Set, Map, array, loop, sort, flatMap, early return, or index maps -->

Apply these patterns in hot paths: render loops, event handlers called frequently, data processing pipelines. Skip them for code that runs once or rarely — the gains are real but small in isolation, and they compound when applied to high-frequency code.

---

Set and Map for O(1) Lookups

**Impact:** LOW-MEDIUM — O(n) to O(1) per membership check

Array `.includes()` scans every element. Converting to a `Set` or `Map` makes repeated lookups constant time — the larger the collection and the more checks you perform, the more this compounds.

**Instead of:**

const allowedIds = ['a', 'b', 'c', ...]
items.filter(item => allowedIds.includes(item.id)) // O(n) per item

**Use:**

const allowedIds = new Set(['a', 'b', 'c', ...])
items.filter(item => allowedIds.has(item.id)) // O(1) per item

Build the Set once outside the loop; pay the O(n) construction cost once rather than O(n) per lookup.

---

Index Maps for Repeated Lookups

**Impact:** LOW-MEDIUM — O(n) to O(1) per lookup; 1M ops to 2K ops for 1000×1000 case

Multiple `.find()` calls over the same array perform O(n) work each time. Building a Map once pays O(n) upfront and makes every subsequent lookup O(1).

**Instead of:**

function processOrders(orders: Order[], users: User[]) {
  return orders.map(order => ({
    ...order,
    user: users.find(u => u.id === order.userId) // O(n) per order
  }))
}

**Use:**

function processOrders(orders: Order[], users: User[]) {
  const userById = new Map(users.map(u => [u.id, u])) // O(n) once

  return orders.map(order => ({
    ...order,
    user: userById.get(order.userId) // O(1) per order
  }))
}

For 1000 orders × 1000 users: 1,000,000 comparisons reduced to ~2,000.

---

Cache Function Results

**Impact:** MEDIUM — avoids redundant computation for repeated calls with same inputs

When the same function is called repeatedly with the same inputs — especially in render loops — a module-level Map eliminates recomputation. This differs from `useMemo` in that it works anywhere (utilities, event handlers), not just inside React components.

**Instead of:**

function ProjectList({ projects }: { projects: Project[] }) {
  return (
    <div>
      {projects.map(project => {
        const slug = slugify(project.name) // recomputed on every render
        return <ProjectCard key={project.id} slug={slug} />
      })}
    </div>
  )
}

**Use:**

const slugifyCache = new Map<string, string>()

function cachedSlugify(text: string): string {
  if (slugifyCache.has(text)) return slugifyCache.get(text)!
  const result = slugify(text)
  slugifyCache.set(text, result)
  return result
}

For single-value functions, a simple variable cache works:

let isLoggedInCache: boolean | null = null

function isLoggedIn(): boolean {
  if (isLoggedInCache !== null) return isLoggedInCache
  isLoggedInCache = document.cookie.includes('auth=')
  return isLoggedInCache
}

function onAuthChange() {
  isLoggedInCache = null // invalidate on change
}

---

Cache Property Access in Loops

**Impact:** LOW-MEDIUM — reduces object traversal in hot loops

Deep property chains (`obj.config.settings.value`) re-traverse the object graph on every iteration. Caching the resolved value before the loop eliminates that overhead for the duration of the loop.

**Instead of:**

for (let i = 0; i < arr.length; i++) {
  process(obj.config.settings.value) // 3 property lookups × N iterations
}

**Use:**

const value = obj.config.settings.value // 3 lookups once
const len = arr.length                  // 1 lookup once
for (let i = 0; i < len; i++) {
  process(value)
}

---

Combine Array Iterations

**Impact:** LOW-MEDIUM — reduces iterations over large arrays

Multiple chained `.filter()` calls each traverse the full array. A single `for...of` loop with multiple conditionals does the same work in one pass.

**Instead of:**

const admins = users.filter(u => u.isAdmin)    // pass 1
const testers = users.filter(u => u.isTester)  // pass 2
const inactive = users.filter(u => !u.isActive) // pass 3

**Use:**

const admins: User[] = []
const testers: User[] = []
const inactive: User[] = []

for (const user of users) {
  if (user.isAdmin) admins.push(user)
  if (user.isTester) testers.push(user)
  if (!user.isActive) inactive.push(user)
}

---

Early Returns

**Impact:** LOW-MEDIUM — avoids unnecessary computation when result is already determined

Returning as soon as an answer is known skips all remaining iterations and branches. Most valuable when the early-exit condition is frequently true or when the remaining computation is expensive.

**Instead of:**

function validateUsers(users: User[]) {
  let hasError = false
  let errorMessage = ''

  for (const user of users) {
    if (!user.email) { hasError = true; errorMessage = 'Email required' }
    if (!user.name) { hasError = true; errorMessage = 'Name required' }
    // Continues scanning even after first error found
  }

  return hasError ? { valid: false, error: errorMessage } : { valid: true }
}

**Use:**

function validateUsers(users: User[]) {
  for (const user of users) {
    if (!user.email) return { valid: false, error: 'Email required' }
    if (!user.name) return { valid: false, error: 'Name required' }
  }
  return { valid: true }
}

---

flatMap Over filter + map

**Impact:** LOW-MEDIUM — eliminates intermediate array and reduces iterations

`.map().filter(Boolean)` creates an intermediate array and iterates twice. `.flatMap()` transforms and filters in a single pass with no intermediate allocation.

**Instead of:**

const userNames = users
  .map(user => user.isActive
Read more
Ships withvexjoy-agent

Essays and writing behind this toolkit live at vexjoy.com. AI agents skip steps. "Looks correct" replaces running tests. "Trivial change" replaces verification.

Get the whole plugin, auto-invoked