You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将异步函数结果传递给事件处理程序?CSS主题下载问题

Fixing "NetworkError when attempting to fetch resource" in CSS Variable Replacement & Download Workflow

Let's break down what's going wrong with your code and fix it step by step. The main issues are incorrect async iteration, unhandled default browser behavior, and some reliability gaps in your fetch/processing logic.

Problem Breakdown

  1. Misused for await...of: Your cssVars is a plain array (not an async iterator), so wrapping it in for await treats each variable as a Promise—which it's not. This causes unexpected behavior in variable parsing and can break your CSS processing.
  2. Default <a> tag behavior: When you click an <a> element, the browser tries to navigate to its href by default. If you modify href in an async callback, the browser might trigger navigation before your fetch completes, interrupting the request and throwing that NetworkError.
  3. Lack of error handling: You don't check if the fetch succeeded, and there's no fallback if CSS variables can't be retrieved.

Fixed Solution

First, let's fix the stylesheet fetching and variable replacement function:

const fetchStyleSheet = async () => { 
  const res = await fetch("./themes/prism.css"); 
  // Ensure the fetch was successful before proceeding
  if (!res.ok) {
    throw new Error(`Failed to load stylesheet: ${res.statusText}`);
  }
  const orig_css = await res.text(); 
  let updated_css = orig_css; 
  // Simplified regex to match CSS variables
  const regexp = /var\(--[a-zA-Z-]*\)/g; 
  // Handle cases where no variables are found to avoid null errors
  const cssVars = orig_css.match(regexp) || []; 

  // Replace for await with standard for...of (cssVars is a sync array)
  for (const variable of cssVars) { 
    const trimmedVar = variable.slice(6, -1); // Strip `var(--` and `)`
    const styles = getComputedStyle(document.documentElement);
    let value = styles.getPropertyValue(`--${trimmedVar}`).trim();
    
    // Optional: Convert RGB/RGBA values to hex if needed
    value = rgbToHex(value);

    // Only replace if we found a valid value for the variable
    if (value) {
      // Use replaceAll to swap ALL instances of the variable, not just the first
      updated_css = updated_css.replaceAll(variable, value);
    }
  }
  return updated_css;
};

// Helper function to convert RGB/RGBA to hex (optional but useful)
function rgbToHex(rgb) {
  const match = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(\.\d+)?))?\)$/);
  if (!match) return rgb;
  
  const r = parseInt(match[1], 10);
  const g = parseInt(match[2], 10);
  const b = parseInt(match[3], 10);
  const hex = ((r << 16) | (g << 8) | b).toString(16).padStart(6, '0');
  
  // Handle alpha channel if present
  if (match[4]) {
    const alphaHex = Math.round(parseFloat(match[4]) * 255).toString(16).padStart(2, '0');
    return `#${hex}${alphaHex}`;
  }
  return `#${hex}`;
}

Next, fix the download button click handler to prevent default behavior and use Blobs (more reliable than data URIs for larger files):

const main = async () => { 
  const downloadBtn = document.getElementById('download-btn');
  
  downloadBtn.addEventListener('click', async (e) => { 
    // Block the default <a> tag navigation to avoid interrupting our async work
    e.preventDefault();
    
    try {
      const updated_css = await fetchStyleSheet();
      // Create a Blob for the CSS content (better than data URIs for large files)
      const blob = new Blob([updated_css], { type: 'text/css;charset=utf-8' });
      const downloadUrl = URL.createObjectURL(blob);
      
      // Set up the download attributes and trigger the download
      downloadBtn.setAttribute('href', downloadUrl);
      downloadBtn.setAttribute('download', 'prism-theme.css');
      downloadBtn.click();
      
      // Clean up the object URL to avoid memory leaks
      setTimeout(() => URL.revokeObjectURL(downloadUrl), 100);
    } catch (err) {
      // Log errors for debugging and notify the user
      console.error('Error creating custom stylesheet:', err);
      alert('Failed to download your custom theme. Check the browser console for details.');
    }
  });
};

main();

Key Improvements Explained

  • Removed for await: Since cssVars is a standard array, for...of works perfectly here and avoids Promise-related bugs.
  • Prevented default behavior: e.preventDefault() stops the browser from trying to navigate before your fetch and processing finish, which fixes the NetworkError.
  • Used Blob instead of data URI: Blobs handle larger files better and avoid encoding issues that can come with encodeURIComponent.
  • Added error handling: We now check fetch success, catch errors, and give user feedback—making debugging much easier.
  • Optional RGB-to-hex conversion: If your custom colors are applied as RGB values, this helper converts them to hex for cleaner CSS output.

Quick Checks to Ensure Success

  • Verify the path ./themes/prism.css is correct: Test it directly in your browser's address bar to make sure it loads the stylesheet.
  • Confirm your custom CSS variables are applied to document.documentElement (the <html> tag) before clicking download.

内容的提问来源于stack exchange,提问作者Dave.Q

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 10:02:42