All skills
jeffallan avatar

/javascript-pro

@efebc44
by jeffallanjeffallan/claude-skills12k stars
1,124

Writes, debugs, and refactors JavaScript code using modern ES2023+ features, async/await patterns, ESM module systems, and Node.js APIs. Use when building vanilla JavaScript applications, implementing Promise-based async flows, optimising browser or Node.js performance, working with Web Workers or Fetch API, or reviewing .js/.mjs/.cjs files for correctness and best practices.

Use this Skill: https://skilld.dev/gh/jeffallan/claude-skills/javascript-pro

This session only. Nothing lands on disk.

referencesasync-patterns.md

≈2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Asynchronous Patterns

Promise Patterns

// Promise creation
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

const fetchWithTimeout = (url, timeout = 5000) => {
  return Promise.race([
    fetch(url),
    delay(timeout).then(() => Promise.reject(new Error('Timeout')))
  ]);
};

// Promise composition
const fetchUserData = async (userId) => {
  const user = await fetch(`/api/users/${userId}`).then(r => r.json());
  const posts = await fetch(`/api/users/${userId}/posts`).then(r => r.json());
  return { user, posts };
};

Async/Await Best Practices

// Parallel execution with Promise.all
const fetchAllData = async () => {
  const [users, posts, comments] = await Promise.all([
    fetch('/api/users').then(r => r.json()),
    fetch('/api/posts').then(r => r.json()),
    fetch('/api/comments').then(r => r.json())
  ]);
  return { users, posts, comments };
};

// Sequential when order matters
const processSteps = async () => {
  const step1 = await executeStep1();
  const step2 = await executeStep2(step1);
  const step3 = await executeStep3(step2);
  return step3;
};

// Conditional parallel execution
const loadUserProfile = async (userId, includeHistory = false) => {
  const userPromise = fetchUser(userId);
  const settingsPromise = fetchSettings(userId);

  const promises = [userPromise, settingsPromise];
  if (includeHistory) {
    promises.push(fetchHistory(userId));
  }

  const [user, settings, history] = await Promise.all(promises);
  return { user, settings, history };
};

Error Handling Strategies

// Try-catch with specific error handling
const safeApiCall = async (url) => {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    return await response.json();
  } catch (error) {
    if (error.name === 'TypeError') {
      console.error('Network error:', error);
    } else if (error.name === 'SyntaxError') {
      console.error('Invalid JSON:', error);
    }
    throw error;
  }
};

// Custom error classes
class ApiError extends Error {
  constructor(status, message, data) {
    super(message);
    this.name = 'ApiError';
    this.status = status;
    this.data = data;
  }
}

const fetchApi = async (endpoint) => {
  const response = await fetch(endpoint);
  if (!response.ok) {
    const data = await response.json().catch(() => ({}));
    throw new ApiError(response.status, response.statusText, data);
  }
  return response.json();
};

// Retry logic with exponential backoff
const retryWithBackoff = async (fn, maxRetries = 3) => {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      const delay = Math.min(1000 * 2 ** i, 10000);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
};

Promise Combinators

// Promise.allSettled - wait for all, regardless of rejection
const results = await Promise.allSettled([
  fetch('/api/users'),
  fetch('/api/posts'),
  fetch('/api/invalid')
]);

results.forEach((result, index) => {
  if (result.status === 'fulfilled') {
    console.log(`Success ${index}:`, result.value);
  } else {
    console.error(`Failed ${index}:`, result.reason);
  }
});

// Promise.any - first successful result
const fastestMirror = await Promise.any([
  fetch('https://mirror1.example.com/data'),
  fetch('https://mirror2.example.com/data'),
  fetch('https://mirror3.example.com/data')
]);

// Promise.race - first settled (resolved or rejected)
const raceResult = await Promise.race([
  fetchFromCache(),
  fetchFromNetwork()
]);

Async Generators

// Async generator for pagination
async function* fetchPaginatedData(baseUrl) {
  let page = 1;
  let hasMore = true;

  while (hasMore) {
    const response = await fetch(`${baseUrl}?page=${page}`);
    const data = await response.json();

    yield data.items;

    hasMore = data.hasMore;
    page++;
  }
}

// Usage
for await (const items of fetchPaginatedData('/api/items')) {
  processItems(items);
}

// Async generator with error handling
async function* streamWithRetry(source) {
  let retries = 3;

  while (retries > 0) {
    try {
      for await (const chunk of source) {
        yield chunk;
      }
      break;
    } catch (error) {
      retries--;
      if (retries === 0) throw error;
      await delay(1000);
    }
  }
}

Concurrent Queue Management

// Limit concurrent operations
class AsyncQueue {
  #queue = [];
  #running = 0;
  #maxConcurrent;

  constructor(maxConcurrent = 3) {
    this.#maxConcurrent = maxConcurrent;
  }

  async run(fn) {
    while (this.#running >= this.#maxConcurrent) {
      await new Promise(resolve => this.#queue.push(resolve));
    }

    this.#running++;
    try {
      return await fn();
    } finally {
      this.#running--;
      const resolve = this.#queue.shift();
      if (resolve) resolve();
    }
  }
}

// Usage
const queue = new AsyncQueue(2);
const results = await Promise.all(
  urls.map(url => queue.run(() => fetch(url)))
);

Event Loop Understanding

// Microtasks vs Macrotasks
console.log('1: Synchronous');

setTimeout(() => console.log('2: Macrotask (setTimeout)'), 0);

Promise.resolve().then(() => console.log('3: Microtask (Promise)'));

queueMicrotask(() => console.log('4: Microtask (queueMicrotask)'));

console.log('5: Synchronous');

// Output order: 1, 5, 3, 4, 2

// Avoid blocking the event loop
const processLargeArray = async (items) => {
  const results = [];
  const chunkSize = 100;

  for (let i = 0; i < items.length; i += chunkSize) {
    const chunk = items.slice(i, i + chunkSize);
    results.push(...chunk.map(processItem));

    // Yield to event loop
    await new Promise(resolve => setTimeout(resolve, 0));
  }

  return results;
};

AbortController for Cancellation

// Abort fetch requests
const controller = new AbortController();
const { signal } = controller;

setTimeout(() => controller.abort(), 5000);

try {
  const response = await fetch('/api/data', { signal });
  const data = await response.json();
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('Request aborted');
  }
}

// Abort multiple operations
const multiAbort = async () => {
  const controller = new AbortController();

  try {
    const [users, posts] = await Promise.all([
      fetch('/api/users', { signal: controller.signal }),
      fetch('/api/posts', { signal: controller.signal })
    ]);
  } catch (error) {
    controller.abort();
    throw error;
  }
};

Stream Processing

// Process ReadableStream
const processStream = async (url) => {
  const response = await fetch(url);
  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  let result = '';
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    result += decoder.decode(value, { stream: true });
  }

  return result;
};

// Transform streams
const transformStream = new TransformStream({
  transform(chunk, controller) {
    const transformed = chunk.toString().toUpperCase();
    controller.enqueue(transformed);
  }
});

const response = await fetch('/data');
const transformed = response.body.pipeThrough(transformStream);

Quick Reference

Pattern Use Case Example
Promise.all() Parallel, fail-fast await Promise.all([p1, p2])
Promise.allSettled() Parallel, all results await Promise.allSettled([p1, p2])
Promise.race() First to complete await Promise.race([p1, p2])
Promise.any() First to succeed await Promise.any([p1, p2])
async function* Async iteration for await (const x of gen())
AbortController Cancellation fetch(url, { signal })
queueMicrotask() Priority microtask queueMicrotask(fn)

Source: SKILL.md on GitHub

1 alert17d5 checks · Risk CRITICAL
  • Gen Agent Trust Hub17d

    The skill has been flagged by multiple automated security scanners for containing malicious content. Specifically, the documentation URL is blacklisted by reputation services, and the main skill file (SKILL.md) has been identified as having a malicious reputation (FileRepMalware). Additionally, the skill's capability to process external code files combined with its access to sensitive system APIs (network, file system, subprocess) creates a significant attack surface for indirect prompt injection.

  • Socket17d

    1 alert: gptAnomaly

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer6mo

    6 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at efebc44. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 5 months ago
Other metadata
metadata
{
  "author": "https://github.com/Jeffallan",
  "version": "1.1.0",
  "domain": "language",
  "triggers": "JavaScript, ES2023, async await, Node.js, vanilla JavaScript, Web Workers, Fetch API, browser API, module system",
  "role": "specialist",
  "scope": "implementation",
  "output-format": "code",
  "related-skills": "fullstack-guardian"
}

README badge

README badge for jeffallan/claude-skills/javascript-pro