Token导航 LogoToken导航TokenDH.com
研究检索操作浏览器github未标认证来源可访问许可证需确认审计通过

js-performance-patternsjs 性能模式

Agent Skill

js-performance-patterns 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

6,365

周安装

260

GitHub Stars

173

下载量

2,059
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:js-performance-patterns(js 性能模式)
来源仓库:https://github.com/patternsdev/skills
仓库路径:skills/js-performance-patterns
安装命令:
npx skills add https://github.com/patternsdev/skills --skill js-performance-patterns
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/patternsdev/skills --skill js-performance-patterns

简介

汇集前端性能优化的通用编码模式。适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

  • 涵盖懒加载、缓存策略与渲染批处理技巧。
  • 每种模式附带适用场景与注意事项说明。
  • 实施前应在真实设备上测量性能指标变化。
  • js-performance-patterns 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

JavaScript Performance Patterns

Table of Contents

Runtime performance micro-patterns for JavaScript hot paths. These patterns matter most in tight loops, frequent callbacks (scroll, resize, animation frames), and data-heavy operations. They apply to any JavaScript environment — React, Vue, vanilla, Node.js.

When to Use

Reference these patterns when:

  • Profiling reveals a hot function or tight loop
  • Processing large datasets (1,000+ items)
  • Handling high-frequency events (scroll, mousemove, resize)
  • Optimizing build-time or server-side scripts
  • Reviewing code for performance in critical paths

Instructions

  • Apply these patterns only in measured hot paths — code that runs frequently or processes large datasets. Don't apply them to cold code paths where readability is more important than nanosecond gains.

Details

Overview

Micro-optimizations are not a substitute for algorithmic improvements. Address the algorithm first (O(n^2) to O(n), removing waterfalls, reducing DOM mutations). Once the algorithm is right, these patterns squeeze additional performance from hot paths.


1. Use Set and Map for Lookups

Impact: HIGH for large collections — O(1) vs O(n) per lookup.

Array methods like .includes(), .find(), and .indexOf() scan linearly. For repeated lookups against the same collection, convert to Set or Map first.

Avoid — O(n) per check:

const allowedIds = ['a', 'b', 'c', /* ...hundreds more */]

function isAllowed(id: string) {
  return allowedIds.includes(id) // scans entire array
}

items.filter(item => allowedIds.includes(item.id)) // O(n * m)

Prefer — O(1) per check:

const allowedIds = new Set(['a', 'b', 'c', /* ...hundreds more */])

function isAllowed(id: string) {
  return allowedIds.has(id)
}

items.filter(item => allowedIds.has(item.id)) // O(n)

For key-value lookups, use Map instead of scanning an array of objects:

// Avoid
const users = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
const user = users.find(u => u.id === targetId) // O(n)

// Prefer
const userMap = new Map(users.map(u => [u.id, u]))
const user = userMap.get(targetId) // O(1)

2. Batch DOM Reads and Writes

Impact: HIGH — Prevents layout thrashing.

Interleaving DOM reads (e.g., offsetHeight, getBoundingClientRect) with DOM writes (e.g., style.height =...) forces the browser to recalculate layout multiple times. Batch all reads first, then all writes.

Avoid — layout thrashing (read/write/read/write):

elements.forEach(el => {
  const height = el.offsetHeight    // read → forces layout
  el.style.height = `${height * 2}px` // write
})
// Each iteration forces a layout recalculation

Prefer — batched reads then writes:

// Read phase
const heights = elements.map(el => el.offsetHeight)

// Write phase
elements.forEach((el, i) => {
  el.style.height = `${heights[i] * 2}px`
})

For complex cases, use requestAnimationFrame to defer writes to the next frame, or use a library like fastdom.

CSS class approach — single reflow:

// Avoid multiple style mutations
el.style.width = '100px'
el.style.height = '200px'
el.style.margin = '10px'

// Prefer — one reflow
el.classList.add('expanded')
// or
el.style.cssText = 'width:100px;height:200px;margin:10px;'

3. Cache Property Access in Tight Loops

Impact: MEDIUM — Reduces repeated property resolution.

Accessing deeply nested properties or array .length in every iteration adds overhead in tight loops.

Avoid:

for (let i = 0; i < data.items.length; i++) {
  process(data.items[i].value.nested.prop)
}

Prefer:

const { items } = data
for (let i = 0, len = items.length; i < len; i++) {
  const val = items[i].value.nested.prop
  process(val)
}

This matters for arrays with 10,000+ items or when called at 60fps. For small arrays or infrequent calls, the readable version is fine.


4. Memoize Expensive Function Results

Impact: MEDIUM-HIGH — Avoids recomputing the same result.

When a pure function is called repeatedly with the same arguments, cache the result.

Simple single-value cache:

function memoize<T extends (...args: any[]) => any>(fn: T): T {
  let lastArgs: any[] | undefined
  let lastResult: any

  return ((...args: any[]) => {
    if (lastArgs && args.every((arg, i) => Object.is(arg, lastArgs![i]))) {
      return lastResult
    }
    lastArgs = args
    lastResult = fn(...args)
    return lastResult
  }) as T
}

const expensiveCalc = memoize((data: number[]) => {
  return data.reduce((sum, n) => sum + heavyTransform(n), 0)
})

Multi-key cache with Map:

const cache = new Map<string, Result>()

function getResult(key: string): Result {
  if (cache.has(key)) return cache.get(key)!
  const result = computeExpensiveResult(key)
  cache.set(key, result)
  return result
}

For caches that can grow unbounded, use an LRU strategy or WeakMap for object keys.


5. Combine Iterations Over the Same Data

Impact: MEDIUM — Single pass instead of multiple.

Chaining .filter().map().reduce() creates intermediate arrays and iterates the data multiple times. For large arrays in hot paths, combine into a single loop.

Avoid — 3 iterations, 2 intermediate arrays:

const result = users
  .filter(u => u.active)
  .map(u => u.name)
  .reduce((acc, name) => acc + name + ', ', '')

Prefer — single pass:

let result = ''
for (const u of users) {
  if (u.active) {
    result += u.name + ', '
  }
}

For small arrays (< 100 items), the chained version is fine and more readable. Optimize only when profiling shows it matters.


6. Short-Circuit with Length Checks First

Impact: LOW-MEDIUM — Avoids expensive operations on empty inputs.

Before running expensive comparisons or transformations, check if the input is empty.

function findMatchingItems(items: Item[], query: string): Item[] {
  if (items.length === 0 || query.length === 0) return []

  const normalized = query.toLowerCase()
  return items.filter(item =>
    item.name.toLowerCase().includes(normalized)
  )
}

7. Return Early to Skip Unnecessary Work

Impact: LOW-MEDIUM — Reduces average-case execution.

Structure functions to exit as soon as possible for common non-matching cases.

Avoid — always does full work:

function processEvent(event: AppEvent) {
  let result = null
  if (event.type === 'click') {
    if (event.target && event.target.matches('.actionable')) {
      result = handleAction(event)
    }
  }
  return result
}

Prefer — exits early:

function processEvent(event: AppEvent) {
  if (event.type !== 'click') return null
  if (!event.target?.matches('.actionable')) return null
  return handleAction(event)
}

8. Hoist RegExp and Constant Creation Outside Loops

Impact: LOW-MEDIUM — Avoids repeated compilation.

Creating RegExp objects or constant values inside loops or frequently-called functions wastes CPU.

Avoid — compiles regex 10,000 times:

function validate(items: string[]) {
  return items.filter(item => {
    const pattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
    return pattern.test(item)
  })
}

Prefer — compile once:

const EMAIL_PATTERN = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/

function validate(items: string[]) {
  return items.filter(item => EMAIL_PATTERN.test(item))
}

9. Use toSorted(), toReversed(), toSpliced() for Immutability

Impact: LOW — Correct immutability without manual copying.

The new non-mutating array methods avoid the [...arr].sort() pattern and communicate intent more clearly.

Avoid — manual copy then mutate:

const sorted = [...items].sort((a, b) => a.price - b.price)
const reversed = [...items].reverse()
const without = [...items]; without.splice(index, 1)

Prefer — non-mutating methods:

const sorted = items.toSorted((a, b) => a.price - b.price)
const reversed = items.toReversed()
const without = items.toSpliced(index, 1)

These are available in all modern browsers and Node.js 20+.


10. Use requestAnimationFrame for Visual Updates

Impact: MEDIUM — Syncs with the browser's render cycle.

DOM updates triggered outside the rendering cycle (from timers, event handlers, etc.) can cause jank. Batch visual updates inside requestAnimationFrame.

Avoid — updates outside render cycle:

window.addEventListener('scroll', () => {
  progressBar.style.width = `${getScrollPercent()}%`
  counter.textContent = `${getScrollPercent()}%`
}, { passive: true })

Prefer — synced to render:

let ticking = false

window.addEventListener('scroll', () => {
  if (!ticking) {
    requestAnimationFrame(() => {
      const pct = getScrollPercent()
      progressBar.style.width = `${pct}%`
      counter.textContent = `${pct}%`
      ticking = false
    })
    ticking = true
  }
}, { passive: true })

11. Use structuredClone for Deep Copies

Impact: LOW — Correct deep cloning without libraries.

structuredClone() handles circular references, typed arrays, Dates, RegExps, Maps, and Sets — unlike JSON.parse(JSON.stringify()).

// Avoid — loses Dates, Maps, Sets, undefined values
const copy = JSON.parse(JSON.stringify(original))

// Prefer — handles all standard types
const copy = structuredClone(original)

Note: structuredClone cannot clone functions or DOM nodes. For those cases, implement a custom clone.


12. Prefer Map Over Plain Objects for Dynamic Keys

Impact: LOW-MEDIUM — Better performance for frequent additions/deletions.

V8 optimizes plain objects for static shapes. When keys are added and removed dynamically (caches, counters, registries), Map provides consistently better performance.

// Avoid for dynamic keys
const counts: Record<string, number> = {}
items.forEach(item => {
  counts[item.category] = (counts[item.category] || 0) + 1
})

// Prefer for dynamic keys
const counts = new Map<string, number>()
items.forEach(item => {
  counts.set(item.category, (counts.get(item.category) ?? 0) + 1)
})

Source

Patterns from patterns.dev — JavaScript performance guidance for the broader web engineering community.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

36.47%
按下载量换算751

Claude

30.45%
按下载量换算627

Cursor

18.69%
按下载量换算385

Gemini CLI

9.96%
按下载量换算205

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

操作浏览器

该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills