浏览器常见面试题及答案实操续篇之深度解析与典型例题详解

54 阅读9分钟

浏览器常见面试题及答案(续)

五、前端性能优化策略及应用实例

1. 懒加载组件封装方法

图片懒加载是前端性能优化的重要手段,以下是一个基于Intersection Observer API的懒加载组件封装实现:

class LazyLoad {
  constructor(options = {}) {
    this.options = {
      root: null,
      rootMargin: '0px',
      threshold: 0.1,
      dataSrc: 'data-src',
      ...options
    };
    this.observer = null;
    this.init();
  }

  init() {
    // 检查浏览器是否支持IntersectionObserver
    if ('IntersectionObserver' in window) {
      this.observer = new IntersectionObserver(this.handleIntersect.bind(this), this.options);
      this.observeElements();
    } else {
      // 降级处理:立即加载所有图片
      this.loadAllImages();
    }
  }

  observeElements() {
    const images = document.querySelectorAll(`img[${this.options.dataSrc}]`);
    images.forEach(img => this.observer.observe(img));
  }

  handleIntersect(entries) {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        const src = img.getAttribute(this.options.dataSrc);
        if (src) {
          img.src = src;
          img.removeAttribute(this.options.dataSrc);
          img.classList.add('loaded');
        }
        this.observer.unobserve(img);
      }
    });
  }

  loadAllImages() {
    const images = document.querySelectorAll(`img[${this.options.dataSrc}]`);
    images.forEach(img => {
      const src = img.getAttribute(this.options.dataSrc);
      if (src) {
        img.src = src;
        img.removeAttribute(this.options.dataSrc);
        img.classList.add('loaded');
      }
    });
  }
}

// 使用示例
document.addEventListener('DOMContentLoaded', () => {
  new LazyLoad({
    rootMargin: '200px 0px', // 提前200px加载
    threshold: 0.2
  });
});

2. 防抖与节流函数封装

在处理高频触发事件时,防抖(Debounce)和节流(Throttle)是常用的优化手段:

// 防抖函数:延迟执行,重复触发则重置计时器
export function debounce(fn, delay = 300, immediate = false) {
  let timer = null;
  
  return function(...args) {
    const context = this;
    
    // 立即执行的情况
    if (immediate && !timer) {
      fn.apply(context, args);
    }
    
    // 清除之前的计时器
    if (timer) clearTimeout(timer);
    
    // 设置新的计时器
    timer = setTimeout(() => {
      if (!immediate) {
        fn.apply(context, args);
      }
      timer = null;
    }, delay);
  };
}

// 节流函数:固定间隔执行一次
export function throttle(fn, limit = 300) {
  let inThrottle;
  let lastFn;
  let lastTime;
  
  return function(...args) {
    const context = this;
    
    if (!inThrottle) {
      fn.apply(context, args);
      lastTime = Date.now();
      inThrottle = true;
    } else {
      clearTimeout(lastFn);
      lastFn = setTimeout(() => {
        if (Date.now() - lastTime >= limit) {
          fn.apply(context, args);
          lastTime = Date.now();
        }
      }, Math.max(limit - (Date.now() - lastTime), 0));
    }
  };
}

3. 组件化缓存策略实现

在现代前端框架中,合理的缓存策略可以显著提升应用性能:

// 基于Vue 3的组件缓存实现示例
import { ref, computed, onMounted, onUnmounted } from 'vue';

export default {
  name: 'CachedComponent',
  props: {
    cacheKey: {
      type: String,
      required: true
    },
    fetchData: {
      type: Function,
      required: true
    },
    cacheTime: {
      type: Number,
      default: 60 * 1000 // 默认缓存1分钟
    }
  },
  setup(props) {
    const cacheStorage = ref({});
    const cacheExpiry = ref({});
    const data = ref(null);
    const isLoading = ref(false);
    const error = ref(null);
    
    // 检查缓存是否有效
    const isCacheValid = computed(() => {
      const expiry = cacheExpiry.value[props.cacheKey];
      return expiry && Date.now() < expiry;
    });
    
    // 从缓存中获取数据
    const getCache = () => {
      if (isCacheValid.value) {
        return cacheStorage.value[props.cacheKey];
      }
      return null;
    };
    
    // 设置缓存
    const setCache = (value) => {
      cacheStorage.value[props.cacheKey] = value;
      cacheExpiry.value[props.cacheKey] = Date.now() + props.cacheTime;
    };
    
    // 加载数据
    const loadData = async () => {
      isLoading.value = true;
      error.value = null;
      
      try {
        // 优先使用缓存
        const cached = getCache();
        if (cached) {
          data.value = cached;
          return;
        }
        
        // 从服务器获取数据
        const result = await props.fetchData();
        data.value = result;
        setCache(result);
      } catch (err) {
        error.value = err;
      } finally {
        isLoading.value = false;
      }
    };
    
    // 初始化加载
    onMounted(() => {
      loadData();
    });
    
    // 清理缓存
    onUnmounted(() => {
      // 可以实现按需清理缓存的逻辑
    });
    
    return {
      data,
      isLoading,
      error,
      refresh: loadData // 提供刷新方法
    };
  }
};

六、浏览器缓存机制与应用实例

1. HTTP缓存配置示例

// Express.js服务器端缓存配置示例
const express = require('express');
const app = express();

// 静态资源缓存配置
app.use('/static', express.static('public', {
  maxAge: 3600 * 1000, // 1小时
  etag: true,
  lastModified: true
}));

// 动态资源缓存控制
app.get('/api/data', (req, res) => {
  // 设置缓存控制头
  res.setHeader('Cache-Control', 'public, max-age=60'); // 60秒公共缓存
  
  // 生成响应数据
  const data = { message: 'Hello World', timestamp: Date.now() };
  res.json(data);
});

// 协商缓存示例
app.get('/api/posts', (req, res) => {
  const { posts, etag } = getPostsFromDatabase();
  
  // 检查客户端发送的ETag
  if (req.headers['if-none-match'] === etag) {
    res.status(304).end();
    return;
  }
  
  // 设置新的ETag
  res.setHeader('ETag', etag);
  res.json(posts);
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

2. Service Worker缓存实现

// service-worker.js
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open('static-v1').then(cache => {
      return cache.addAll([
        '/',
        '/index.html',
        '/styles.css',
        '/main.js',
        '/images/logo.png'
      ]);
    })
  );
});

self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(keys => {
      return Promise.all(
        keys.filter(key => key.startsWith('static-') && key !== 'static-v1')
            .map(key => caches.delete(key))
      );
    })
  );
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(response => {
      // 缓存优先策略
      if (response) return response;
      
      // 从网络获取
      return fetch(event.request).then(networkResponse => {
        // 克隆响应,因为响应只能被使用一次
        const responseToCache = networkResponse.clone();
        
        // 将新的响应添加到缓存
        caches.open('static-v1').then(cache => {
          cache.put(event.request, responseToCache);
        });
        
        return networkResponse;
      });
    })
  );
});

3. Web Storage使用封装

// storage.js - 本地存储封装
export default class Storage {
  constructor(prefix = 'app_') {
    this.prefix = prefix;
  }
  
  // 获取完整的键名
  getKey(key) {
    return `${this.prefix}${key}`;
  }
  
  // 设置本地存储项
  setItem(key, value, expires = null) {
    const item = {
      value,
      expires: expires ? Date.now() + expires : null
    };
    
    try {
      localStorage.setItem(this.getKey(key), JSON.stringify(item));
    } catch (e) {
      console.error('Failed to set localStorage item:', e);
    }
  }
  
  // 获取本地存储项
  getItem(key) {
    try {
      const itemStr = localStorage.getItem(this.getKey(key));
      if (!itemStr) return null;
      
      const item = JSON.parse(itemStr);
      
      // 检查是否过期
      if (item.expires && Date.now() > item.expires) {
        localStorage.removeItem(this.getKey(key));
        return null;
      }
      
      return item.value;
    } catch (e) {
      console.error('Failed to get localStorage item:', e);
      return null;
    }
  }
  
  // 移除本地存储项
  removeItem(key) {
    try {
      localStorage.removeItem(this.getKey(key));
    } catch (e) {
      console.error('Failed to remove localStorage item:', e);
    }
  }
  
  // 清空本地存储
  clear() {
    try {
      const keysToRemove = [];
      
      // 收集所有需要删除的键
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (key.startsWith(this.prefix)) {
          keysToRemove.push(key);
        }
      }
      
      // 删除这些键
      keysToRemove.forEach(key => localStorage.removeItem(key));
    } catch (e) {
      console.error('Failed to clear localStorage:', e);
    }
  }
}

// 使用示例
const storage = new Storage('myapp_');
storage.setItem('user', { name: 'John', age: 30 }, 3600 * 1000); // 1小时后过期
const user = storage.getItem('user');

七、组件封装最佳实践

1. 通用原则

  1. 单一职责原则:每个组件只负责一个特定的功能或任务
  2. 高内聚低耦合:组件内部联系紧密,与外部依赖尽可能少
  3. 可配置性:通过props提供灵活的配置选项
  4. 无状态与有状态分离:将展示组件和容器组件分离
  5. 生命周期管理:合理使用组件生命周期钩子
  6. 错误边界处理:确保组件在异常情况下仍能正常运行

2. 封装一个通用的模态框组件

以下是一个基于React的通用模态框组件封装示例:

import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';

const Modal = ({ 
  isOpen, 
  onClose, 
  title, 
  children, 
  confirmText = '确认',
  cancelText = '取消',
  onConfirm,
  showFooter = true,
  className = '',
  backdropClassName = '',
  animationDuration = 300
}) => {
  const [isAnimating, setIsAnimating] = useState(false);
  
  // 控制动画
  useEffect(() => {
    if (isOpen) {
      setIsAnimating(true);
    } else {
      // 延迟关闭以完成动画
      setTimeout(() => {
        setIsAnimating(false);
      }, animationDuration);
    }
  }, [isOpen, animationDuration]);
  
  // 点击背景关闭
  const handleBackdropClick = (e) => {
    if (e.target === e.currentTarget) {
      onClose();
    }
  };
  
  // 阻止冒泡,避免点击内容时关闭模态框
  const handleContentClick = (e) => {
    e.stopPropagation();
  };
  
  // 确认按钮点击事件
  const handleConfirm = () => {
    if (onConfirm) {
      onConfirm();
    } else {
      onClose();
    }
  };
  
  return (
    isOpen && (
      <div 
        className={`fixed inset-0 flex items-center justify-center z-50 transition-opacity duration-${animationDuration} ${
          isAnimating ? 'opacity-100' : 'opacity-0'
        } ${backdropClassName}`}
        onClick={handleBackdropClick}
      >
        <div 
          className={`bg-white rounded-lg shadow-xl max-w-md w-full mx-4 transform transition-all duration-${animationDuration} ${
            isAnimating ? 'scale-100 opacity-100' : 'scale-95 opacity-0'
          } ${className}`}
          onClick={handleContentClick}
        >
          {/* 标题 */}
          {title && (
            <div className="px-6 py-4 border-b border-gray-200">
              <h3 className="text-lg font-medium text-gray-900">{title}</h3>
            </div>
          )}
          
          {/* 内容 */}
          <div className="px-6 py-4">{children}</div>
          
          {/* 底部按钮 */}
          {showFooter && (
            <div className="px-6 py-4 border-t border-gray-200 flex justify-end space-x-3">
              <button 
                className="px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
                onClick={onClose}
              >
                {cancelText}
              </button>
              <button 
                className="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
                onClick={handleConfirm}
              >
                {confirmText}
              </button>
            </div>
          )}
        </div>
      </div>
    )
  );
};

Modal.propTypes = {
  isOpen: PropTypes.bool.isRequired,
  onClose: PropTypes.func.isRequired,
  title: PropTypes.node,
  children: PropTypes.node.isRequired,
  confirmText: PropTypes.string,
  cancelText: PropTypes.string,
  onConfirm: PropTypes.func,
  showFooter: PropTypes.bool,
  className: PropTypes.string,
  backdropClassName: PropTypes.string,
  animationDuration: PropTypes.number
};

export default Modal;

3. 使用自定义Hook封装复杂逻辑

// useFetch.js - 封装数据获取逻辑
import { useState, useEffect, useCallback } from 'react';

export const useFetch = (url, initialOptions = {}) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [options, setOptions] = useState(initialOptions);
  
  const fetchData = useCallback(async () => {
    setLoading(true);
    setError(null);
    
    try {
      const response = await fetch(url, options);
      
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      
      const result = await response.json();
      setData(result);
    } catch (err) {
      setError(err);
    } finally {
      setLoading(false);
    }
  }, [url, options]);
  
  useEffect(() => {
    fetchData();
  }, [fetchData]);
  
  const refetch = (newOptions = {}) => {
    setOptions(prev => ({ ...prev, ...newOptions }));
  };
  
  return { data, loading, error, refetch };
};

// 使用示例
const MyComponent = () => {
  const { data, loading, error, refetch } = useFetch('https://api.example.com/data');
  
  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  
  return (
    <div>
      <h1>Data</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
      <button onClick={() => refetch()}>Refresh</button>
    </div>
  );
};

八、浏览器安全与防护措施

1. XSS攻击防护

// 输入过滤函数 - 防止XSS攻击
export function sanitizeInput(input) {
  if (!input) return '';
  
  // 转换特殊字符
  return input
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#039;');
}

// 安全地设置HTML内容
export function setSafeHTML(element, html) {
  if (!element) return;
  
  // 使用DocumentFragment和textContent处理
  const fragment = document.createDocumentFragment();
  const temp = document.createElement('div');
  
  temp.textContent = html;
  while (temp.firstChild) {
    fragment.appendChild(temp.firstChild);
  }
  
  // 清空原内容并添加安全内容
  element.textContent = '';
  element.appendChild(fragment);
}

// 在React中使用示例
const SafeComponent = ({ userInput }) => {
  const safeInput = sanitizeInput(userInput);
  
  return (
    <div 
      className="user-content"
      // 避免直接使用dangerouslySetInnerHTML
      ref={el => el && (el.textContent = safeInput)}
    />
  );
};

2. CSRF防护

// CSRF防护实现 - 在服务端生成和验证CSRF令牌
const crypto = require('crypto');

// 生成CSRF令牌
function generateCSRFToken() {
  return crypto.randomBytes(16).toString('hex');
}

// 设置CSRF令牌到Cookie
function setCSRFTokenCookie(res, token) {
  res.cookie('csrf_token', token, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'strict',
    maxAge: 3600 * 1000 // 1小时
  });
}

// 验证CSRF令牌
function verifyCSRFToken(req) {
  const cookieToken = req.cookies.csrf_token;
  const headerToken = req.headers['x-csrf-token'];
  
  if (!cookieToken || !headerToken) {
    return false;
  }
  
  return cookieToken === headerToken;
}

// Express中间件实现
function csrfProtection(req, res, next) {
  // 对于GET请求,生成并设置新的CSRF令牌
  if (req.method === 'GET') {
    const token = generateCSRFToken();
    setCSRFTokenCookie(res, token);
    res.locals.csrfToken = token; // 可以在视图中使用
    next();
  } 
  // 对于其他请求,验证CSRF令牌
  else {
    if (!verifyCSRFToken(req)) {
      return res.status(403).json({ error: 'CSRF验证失败' });
    }
    next();
  }
}

module.exports = {
  csrfProtection
};

九、性能监控与优化实践

1. 使用Performance API监控性能

// 性能监控工具
class PerformanceMonitor {
  constructor() {
    this.isSupported = 'performance' in window;
    this.markers = new Set();
  }
  
  // 开始性能标记
  start(name) {
    if (!this.isSupported) return;
    
    if (this.markers.has(name)) {
      console.warn(`Performance marker "${name}" already exists`);
      return;
    }
    
    performance.mark(`start_${name}`);
    this.markers.add(name);
  }
  
  // 结束性能标记并计算时间
  end(name) {
    if (!this.isSupported) return null;
    
    if (!this.markers.has(name)) {
      console.warn(`Performance marker "${name}" does not exist`);
      return null;
    }
    
    performance.mark(`end_${name}`);
    performance.measure(name, `start_${name}`, `end_${name}`);
    
    const entry = performance.getEntriesByName(name)[0];
    const duration = entry.duration;
    
    // 清理
    performance.clearMarks(`start_${name}`);
    performance.clearMarks(`end_${name}`);
    performance.clearMeasures(name);
    this.markers.delete(name);
    
    return duration;
  }
  
  // 测量特定函数执行时间
  measureFunction(fn, name = 'function') {
    if (!this.isSupported) {
      return fn();
    }
    
    this.start(name);
    const result = fn();
    const duration = this.end(name);
    
    console.log(`Function "${name}" executed in ${duration.toFixed(2)}ms`);
    return result;
  }
  
  // 监控页面加载时间
  monitorPageLoad() {
    if (!this.isSupported) return;
    
    window.addEventListener('load', () => {
      setTimeout(() => {
        const timing = performance.timing;
        const loadTime = timing.loadEventEnd - timing.navigationStart;
        
        console.log(`Page loaded in ${loadTime}ms`);
        
        // 发送性能数据到分析服务器
        this.sendPerformanceData({
          type: 'page_load',
          loadTime,
          dnsTime: timing.domainLookupEnd - timing.domainLookupStart,
          tcpTime: timing.connectEnd - timing.connectStart,
          requestTime: timing.responseEnd - timing.requestStart,
          domRenderTime: timing.domComplete - timing.domInteractive
        });
      }, 0);
    });
  }
  
  // 发送性能数据到服务器
  sendPerformanceData(data) {
    // 实现将性能数据发送到服务器的逻辑
    console.log('Sending performance data:', data);
    
    // 示例:使用Beacon API发送数据
    if ('navigator' in window && 'sendBeacon' in navigator) {
      navigator.sendBeacon('/api/performance', JSON.stringify(data));
    } else {
      // 回退方案
      fetch('/api/performance', {
        method: 'POST',
        body: JSON.stringify(data),
        keepalive: true
      });
    }
  }
}

// 使用示例
const monitor = new PerformanceMonitor();
monitor.monitorPageLoad();

// 测量某个操作的性能
monitor.start('heavyCalculation');
// 执行一些耗时操作
const result = performHeavyCalculation();
monitor.end('heavyCalculation');

2. 懒加载组件使用示例

<!-- 懒加载图片示例 -->
<img 
  data-src="https://example.com/large-image.jpg" 
  alt="懒加载图片" 
  class="lazy-image"
  loading="lazy" 
/>

<!-- 懒加载脚本示例 -->
<script 
  src="https://example.com/heavy-script.js" 
  async 
  defer 
  class="lazy-script"
></script>

<!-- 懒加载iframe示例 -->
<iframe 
  data-src="https://example.com/embed-content" 
  class="lazy-iframe" 
  loading="lazy"
></iframe>

<script>
  // 简单的懒加载实现
  document.addEventListener('DOMContentLoaded', () => {
    // 懒加载图片
    const lazyImages = document.querySelectorAll('img[data-src]');
    
    lazyImages.forEach(img => {
      const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.dataset.src;
            img.classList.add('loaded');
            observer.unobserve(img);
          }
        });
      });
      
      observer.observe(img);
    });
    
    // 懒加载iframe
    const lazyIframes = document.querySelectorAll('iframe[data-src]');
    
    lazyIframes.forEach(iframe => {
      const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            const iframe = entry.target;
            iframe.src = iframe.dataset.src;
            observer.unobserve(iframe);
          }
        });
      });
      
      observer.observe(iframe);
    });
  });
</script>

十、应用实例与最佳实践

1. 完整的前端性能优化方案

// performance-optimization.js - 前端性能优化工具箱
export class PerformanceOptimizer {
  constructor(options = {}) {
    this.options = {
      lazyLoad: true,
      debounce: true,
      throttle: true,
      resourcePreload: true,
      cache: true,
      ...options
    };
    
    this.init();
  }
  
  init() {
    if (this.options.lazyLoad) {
      this.initLazyLoad();
    }
    
    if (this.options.resourcePreload) {
      this.initResourcePreload();
    }
    
    if (this.options.cache) {
      this.initCache();
    }
  }
  
  // 初始化懒加载
  initLazyLoad() {
    // 图片懒加载
    const lazyImages = document.querySelectorAll('img[data-src]');
    
    if ('IntersectionObserver' in window) {
      const imageObserver = new IntersectionObserver((entries, observer) => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.dataset.src;
            img.classList.add('lazy-loaded');
            observer.unobserve(img);
          }
        });
      });
      
      lazyImages.forEach(img => imageObserver.observe(img));
    } else {
      // 回退方案:立即加载所有图片
      lazyImages.forEach(img => {
        img.src = img.dataset.src;
        img.classList.add('lazy-loaded');
      });
    }
    
    // 脚本懒加载
    const lazyScripts = document.querySelectorAll('script[data-src]');
    
    lazyScripts.forEach(script => {
      const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            const s = document.createElement('script');
            s.src = script.dataset.src;
            s.async = true;
            document.body.appendChild(s);
            observer.unobserve(script);
          }
        });
      }, {
        rootMargin: '500px 0px' // 提前500px加载
      });
      
      observer.observe(script);
    });
  }
  
  // 初始化资源预加载
  initResourcePreload() {
    const preloadLinks = document.querySelectorAll('link[rel="preload"]');
    
    // 监控预加载资源
    preloadLinks.forEach(link => {
      link.addEventListener('load', () => {
        console.log(`Preloaded resource: ${link.href}`);
      });
      
      link.addEventListener('error', () => {
        console.error(`Failed to preload resource: ${link.href}`);
      });
    });
  }
  
  // 初始化缓存策略
  initCache() {
    // 检查是否支持Service Worker
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', () => {
        navigator.serviceWorker.register('/service-worker.js')
          .then(registration => {
            console.log('Service Worker registered with scope:', registration.scope);
          })
          .catch(error => {
            console.error('Service Worker registration failed:', error);
          });
      });
    }
    
    // 初始化本地存储缓存
    this.cache = new CacheManager();
  }
  
  // 创建防抖函数
  debounce(func, wait, immediate) {
    if (!this.options.debounce) return func;
    
    let timeout;
    
    return function() {
      const context = this;
      const args = arguments;
      
      const later = function() {
        timeout = null;
        if (!immediate) func.apply(context, args);
      };
      
      const callNow = immediate && !timeout;
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
      
      if (callNow) func.apply(context, args);
    };
  }
  
  // 创建节流函数
  throttle(func, limit) {
    if (!this.options.throttle) return func;
    
    let inThrottle;
    
    return function() {
      const args = arguments;
      const context = this;
      
      if (!inThrottle) {
        func.apply(context, args);
        inThrottle = true;
        setTimeout(() => inThrottle = false, limit);
      }
    };
  }
  
  // 预加载关键资源
  preloadResource(url, as) {
    const link = document.createElement('link');
    link.rel = 'preload';
    link.href = url;
    link.as = as;
    document.head.appendChild(link);
  }
  
  // 监控性能
  monitorPerformance() {
    // 使用Performance API监控性能
    if ('performance' in window) {
      window.addEventListener('load', () => {
        setTimeout(() => {
          const perfData = performance.timing;
          const loadTime = perfData.loadEventEnd - perfData.navigationStart;
          
          console.log(`页面加载完成: ${loadTime}ms`);
          
          // 可以发送性能数据到服务器
          this.sendPerformanceMetrics({
            loadTime,
            dnsLookup: perfData.domainLookupEnd - perfData.domainLookupStart,
            tcpConnection: perfData.connectEnd - perfData.connectStart,
            requestResponse: perfData.responseEnd - perfData.requestStart,
            domProcessing: perfData.domComplete - perfData.domInteractive
          });
        }, 0);
      });
    }
  }
  
  // 发送性能指标到服务器
  sendPerformanceMetrics(metrics) {
    // 实现发送性能指标的逻辑
    console.log('发送性能指标:', metrics);
    
    // 使用fetch API发送数据
    fetch('/api/performance-metrics', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(metrics)
    });
  }
}

// 缓存管理器
class CacheManager {
  constructor(prefix = 'app-cache-') {
    this.prefix = prefix;
    this.supported = typeof localStorage !== 'undefined';
  }
  
  // 获取缓存
  get(key) {
    if (!this.supported) return null;
    
    const item = localStorage.getItem(`${this.prefix}${key}`);
    
    if (!item) return null;
    
    try {
      const { value, expires } = JSON.parse(item);
      
      if (expires && Date.now() > expires) {
        this.remove(key);
        return null;
      }
      
      return value;
    } catch (e) {
      console.error('Failed to parse cache item:', e);
      this.remove(key);
      return null;
    }
  }
  
  // 设置缓存
  set(key, value, ttl = 3600) { // 默认1小时
    if (!this.supported) return;
    
    const expires = Date.now() + (ttl * 1000);
    
    try {
      localStorage.setItem(
        `${this.prefix}${key}`,
        JSON.stringify({ value, expires })
      );
    } catch (e) {
      console.error('Failed to set cache item:', e);
    }
  }
  
  // 移除缓存
  remove(key) {
    if (!this.supported) return;
    
    localStorage.removeItem(`${this.prefix}${key}`);
  }
  
  // 清空所有缓存
  clear() {
    if (!this.supported) return;
    
    for (let i = localStorage.length - 1; i >= 0; i--) {
      const key = localStorage.key(i);
      if (key.startsWith(this.prefix)) {
        localStorage.removeItem(key);
      }
    }
  }
}

2. 组件化实现方案示例

以下是一个基于Vue的组件化实现方案示例,展示了如何组织和构建前端应用:

// 项目结构示例
my-project/
├── src/
│   ├── components/           // 通用组件
│   │   ├── Button/
│   │   │   ├── Button.vue
│   │   │   └── Button.test.js
│   │   ├── Card/
│   │   │   ├── Card.vue
│   │   │   └── Card.test.js
│   │   └── Modal/
│   │       ├── Modal.vue
│   │       ├── Modal.test.js
│   │       └── useModal.js
│   ├── composables/          // 组合式函数
│   │   ├── useFetch.js
│   │   ├── useLocalStorage.js
│   │   └── useDebounce.js
│   ├── layouts/              // 布局组件
│   │   ├── DefaultLayout.vue
│   │   └── BlankLayout.vue
│   ├── pages/                // 页面组件
│   │   ├── Home.vue
│   │   ├── About.vue
│   │   └── Contact.vue
│   ├── plugins/              // 插件
│   │   ├── axios.js
│   │   └── vue-router.js
│   ├── stores/               // 状态管理
│   │   ├── user.js
│   │   └── products.js
│   ├── utils/                // 工具函数
│   │   ├── formatters.js
│   │   └── validators.js
│   ├── App.vue
│   └── main.js
└── package.json

3. 浏览器安全防护集成

// security.js - 浏览器安全防护工具箱
export class SecurityGuard {
  constructor(options = {}) {
    this.options = {
      xssProtection: true,
      csrfProtection: true,
      clickjackingProtection: true,
      contentSecurityPolicy: true,
      ...options
    };
    
    this.init();
  }
  
  init() {
    if (this.options.xssProtection) {
      this.initXSSProtection();
    }
    
    if (this.options.csrfProtection) {
      this.initCSRFProtection();
    }
    
    if (this.options.clickjackingProtection) {
      this.initClickjackingProtection();
    }
    
    if (this.options.contentSecurityPolicy) {
      this.initContentSecurityPolicy();
    }
  }
  
  // XSS防护
  initXSSProtection() {
    // 过滤用户输入
    window.sanitizeInput = (input) => {
      if (!input) return '';
      
      // 转换特殊字符
      return input
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#039;');
    };
    
    // 安全设置HTML
    window.setSafeHTML = (element, html) => {
      if (!element) return;
      
      const temp = document.createElement('div');
      temp.textContent = html;
      element.innerHTML = temp.innerHTML;
    };
  }
  
  // CSRF防护
  initCSRFProtection() {
    // 生成CSRF令牌
    const generateCSRFToken = () => {
      const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
      let token = '';
      
      for (let i = 0; i < 32; i++) {
        token += characters.charAt(Math.floor(random() * characters.length));
      }
      
      return token;
    };
    
    // 设置CSRF令牌到Cookie
    const setCSRFToken = (token) => {
      document.cookie = `csrf_token=${token}; path=/; secure; samesite=strict`;
    };
    
    // 从Cookie获取CSRF令牌
    const getCSRFToken = () => {
      const name = 'csrf_token=';
      const ca = document.cookie.split(';');
      
      for (let i = 0; i < ca.length; i++) {
        let c = ca[i];
        while (c.charAt(0) === ' ') {
          c = c.substring(1);
        }
        if (c.indexOf(name) === 0) {
          return c.substring(name.length, c.length);
        }
      }
      
      return null;
    };
    
    // 为AJAX请求添加CSRF令牌
    if (window.XMLHttpRequest) {
      const originalOpen = XMLHttpRequest.prototype.open;
      
      XMLHttpRequest.prototype.open = function() {
        originalOpen.apply(this, arguments);
        
        const csrfToken = getCSRFToken();
        if (csrfToken && this.method !== 'GET') {
          this.setRequestHeader('X-CSRF-Token', csrfToken);
        }
      };
    }
    
    // 为Fetch API添加CSRF令牌
    if (window.fetch) {
      const originalFetch = window.fetch;
      
      window.fetch = function(input, init = {}) {
        const csrfToken = getCSRFToken();
        
        if (csrfToken && init.method && init.method !== 'GET') {
          init.headers = {
            ...init.headers,
            'X-CSRF-Token': csrfToken
          };
        }
        
        return originalFetch(input, init);
      };
    }
    
    // 初始化CSRF令牌
    if (!getCSRFToken()) {
      setCSRFToken(generateCSRFToken());
    }
  }
  
  // 点击劫持防护
  initClickjackingProtection() {
    // 设置X-Frame-Options头
    const setXFrameOptions = () => {
      // 注意:这实际上需要在服务器端设置,这里只是示例
      document.addEventListener('DOMContentLoaded', () => {
        const meta = document.createElement('meta');
        meta.httpEquiv = 'X-Frame-Options';
        meta.content = 'SAMEORIGIN';
        document.head.appendChild(meta);
      });
    };
    
    // 自我防御脚本
    const selfDefenseScript = () => {
      if (window.top !== window.self) {
        window.top.location = window.self.location;
      }
    };
    
    // 执行防御措施
    setXFrameOptions();
    selfDefenseScript();
  }
  
  // 内容安全策略
  initContentSecurityPolicy() {
    // 注意:这实际上需要在服务器端设置,这里只是示例
    document.addEventListener('DOMContentLoaded', () => {
      const meta = document.createElement('meta');
      meta.httpEquiv = 'Content-Security-Policy';
      meta.content = "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'";
      document.head.appendChild(meta);
    });
  }
  
  // 防止敏感数据泄露
  preventDataLeakage() {
    // 防止密码在URL中泄露
    if (window.history && window.history.replaceState) {
      const originalPushState = window.history.pushState;
      const originalReplaceState = window.history.replaceState;
      
      window.history.pushState = function() {
        const url = arguments[2];
        if (url && url.includes('password=')) {
          console.error('敏感数据不应该出现在URL中');
          return;
        }
        originalPushState.apply(this, arguments);
      };
      
      window.history.replaceState = function() {
        const url = arguments[2];
        if (url && url.includes('password=')) {
          console.error('敏感数据不应该出现在URL中');
          return;
        }
        originalReplaceState.apply(this, arguments);
      };
    }
  }
  
  // 验证URL安全
  validateURL(url) {
    try {
      const parsedUrl = new URL(url);
      return parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:';
    } catch (e) {
      return false;
    }
  }
}

以上组件封装和使用方法涵盖了前端开发中的多个关键领域,包括性能优化、安全防护、状态管理等。通过合理使用这些技术和方法,可以构建出高性能、安全可靠的前端应用。在实际项目中,应根据具体需求选择合适的技术方案,并进行适当的调整和优化。


浏览器面试题,浏览器面试答案,浏览器面试深度解析,浏览器典型例题,浏览器原理,前端面试,面试题解析,JavaScript,HTML,CSS, 浏览器渲染机制,浏览器缓存,跨域问题,HTTP 协议,Web 安全



资源地址: pan.quark.cn/s/50438c9ee…