每天一个高级前端知识 - Day 1

3 阅读2分钟

每天一个高级前端知识 - Day 1

今日主题:浏览器渲染流水线深度解析 - 从URL到像素的魔法

核心概念:关键渲染路径(Critical Rendering Path)

浏览器从收到HTML到最终显示像素,经历了以下阶段:

HTML → DOM树
CSS → CSSOM树 → 渲染树 → 布局(Layout) → 绘制(Paint) → 合成(Composite)

🔍 深入细节

1. DOM树构建

  • 字节 → 字符 → 令牌 → 节点 → DOM
  • 阻塞:<script>标签会暂停解析(除非加async/defer

2. CSSOM构建

  • CSS会阻塞渲染(关键CSS内联优化)
  • CSS不会阻塞DOM解析,但会阻塞JS执行(因为JS可能查询样式)

3. 渲染树

  • 过滤display:none<head>等不可见元素
  • visibility:hidden仍在树中(占空间)

4. Layout(回流)

  • 计算每个节点的几何信息(宽高、位置)
  • 触发条件:改变几何属性、添加/删除DOM、改变窗口大小
  • 代价最高,需避免

5. Paint(重绘)

  • 填充像素(颜色、背景、阴影等)
  • 触发条件:改变非几何属性(color, background等)

6. Composite(合成)

  • 将绘制层合并为最终屏幕图像
  • 触发条件:transform、opacity、will-change等(仅合成)

💡 性能优化实战

// ❌ 糟糕实践 - 强制同步布局
const height = element.offsetHeight;  // 读取
element.style.height = height + 10 + 'px'; // 写入

// ✅ 最佳实践 - 批处理读写
// 先读后写
const height = element.offsetHeight;
const width = element.offsetWidth;
// 批量写入
element.style.height = height + 10 + 'px';
element.style.width = width + 10 + 'px';

// 🚀 高级技巧 - 使用requestAnimationFrame
requestAnimationFrame(() => {
  // 在下一帧绘制前批量修改
  element.style.transform = 'translateX(100px)';
});

🎯 今日挑战

实现一个高性能滚动变色导航栏,要求:

  • 滚动超过100px时改变背景色
  • 使用transform而不是top/left实现固定效果
  • 使用IntersectionObserver(避免滚动监听)
参考实现
class PerformanceNavbar {
  constructor() {
    this.navbar = document.querySelector('.navbar');
    this.sentinel = document.createElement('div');
    this.init();
  }
  
  init() {
    // 创建哨兵元素
    this.sentinel.style.position = 'absolute';
    this.sentinel.style.top = '100px';
    this.sentinel.style.height = '1px';
    document.body.prepend(this.sentinel);
    
    // IntersectionObserver比scroll监听性能好100倍+
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (!entry.isIntersecting) {
          this.navbar.classList.add('scrolled');
        } else {
          this.navbar.classList.remove('scrolled');
        }
      });
    });
    
    observer.observe(this.sentinel);
  }
}

明日预告:Event Loop微任务/宏任务底层原理 & 如何写一个零延迟的调度器

保持好奇,持续输出!🔥