LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

js加载对浏览器渲染的影响

freeflydom
2025年7月7日 11:14 本文热度 145

一、浏览器渲染基础:关键渲染路径解析

当浏览器加载网页时,遵循以下关键步骤:

  1. HTML解析 → 2. DOM树构建 → 3. CSSOM构建 → 4. 渲染树构建 → 5. 布局 → 6. 绘制

JavaScript在其中的作用:

graph LR
    A[HTML解析] --> B[遇到JS]
    B -->|同步JS| C[阻塞DOM构建]
    C --> D[执行JS]
    D --> E[继续DOM构建]
    B -->|CSS| F[阻塞渲染]

关键点:在DOM树构建过程中遇到JavaScript时:

  • 如果是外部JS文件:浏览器必须等待JS下载并执行完成
  • 如果是内联JS:浏览器立即执行代码

二、JavaScript加载的阻塞行为验证

2.1 实验:同步JS的阻塞效应

<!DOCTYPE html>
<html>
<head>
  <title>阻塞测试</title>
  <script>
    // 模拟长时间执行
    const start = Date.now();
    while (Date.now() - start < 3000) {}
  </script>
</head>
<body>
  <!-- 这段HTML在JS执行完成前不会渲染 -->
  <h1>3秒后你会看到我</h1>
</body>
</html>

实验结果:页面空白3秒后才显示内容,证明同步

2.2 外部JS文件的阻塞情况

<script src="heavy-script.js"></script>
<!-- 后续内容会被阻塞 -->

问题核心:

  • 网络时间:下载JS文件所需的时间
  • 执行时间:JS解析和执行时间

三、解决方案:打破JS阻塞的四种策略

3.1 async属性:异步加载(适用于独立脚本)

<script src="analytics.js" async></script>

特性:

  • 异步下载,不阻塞HTML解析
  • 下载完成后立即执行,可能中断渲染
  • 执行顺序无法保证

3.2 defer属性:延迟执行(推荐方案)

<script src="main.js" defer></script>

特性:

  • 异步下载,不阻塞HTML解析
  • 执行推迟到DOMContentLoaded事件之前
  • 保持多个脚本的执行顺序

3.3 动态加载:灵活控制

function loadScript(src, callback) {
  const script = document.createElement('script');
  script.src = src;
  script.onload = callback;
  document.head.appendChild(script);
}

优势:完全控制加载时机,可实现按需加载

3.4 模块化加载(ES Modules)

<script type="module">
  import { init } from './app.js';
  init();
</script>

特性:

  • 默认具有defer行为
  • 支持模块依赖解析
  • 现代浏览器原生支持

四、性能优化实战:对比实验数据

加载方式渲染开始时间DOMContentLoaded完全加载时间FCP(ms)TTI(ms)
同步加载3.2s3.5s4.1s32004100
async0.8s2.2s3.0s8003000
defer0.8s1.9s2.8s8002800
动态加载0.8s1.4s2.5s8002500

测试环境:1MB JS文件 + 中等复杂度页面,模拟3G网络

五、避免阻塞的关键实践

5.1 最佳资源加载顺序

<head>
  <!-- 关键CSS优先 -->
  <link rel="stylesheet" href="critical.css">
  
  <!-- 非关键JS异步加载 -->
  <script src="analytics.js" async></script>
  
  <!-- 主要JS延迟加载 -->
  <script src="main.js" defer></script>
</head>

5.2 优化JS执行时间

// 将长任务分解
function processInChunks() {
  const chunkSize = 100;
  let index = 0;
  
  function processChunk() {
    const end = Math.min(index + chunkSize, data.length);
    
    for (; index < end; index++) {
      // 处理数据
    }
    
    if (index < data.length) {
      // 使用requestIdleCallback避免阻塞主线程
      requestIdleCallback(processChunk);
    }
  }
  
  processChunk();
}

5.3 现代浏览器预加载扫描器优化

<link rel="preload" href="critical.js" as="script">
<link rel="preconnect" href="https://cdn.example.com">

六、特殊情况与边界处理

6.1 document.write的陷阱

// 避免在文档加载后使用
document.write('<script src="dangerous.js"></script>');

风险:在DOMContentLoaded之后使用会清空页面

6.2 CSS对JS执行的潜在阻塞

graph TD
    JS[JavaScript执行] -->|需要CSSOM| CSS[CSS加载]
    CSS -->|未完成| Block[阻塞JS执行]
    Block -->|CSSOM就绪| Continue[继续执行JS]

七、性能监测工具实战

Chrome DevTools监测:

// 在控制台中检测长任务
const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    console.log('长任务:', entry);
  }
});
observer.observe({ entryTypes: ['longtask'] });

关键指标:

  • FCP (First Contentful Paint):首次内容渲染
  • TTI (Time to Interactive):可交互时间
  • Long Tasks:超过50ms的任务

小结

  1. 基本原则:

    • 关键路径JS:使用<script defer>
    • 非关键JS:使用<script async>或动态加载
  2. 性能优化进阶:

    // 代码分割 + 按需加载
    import('./module')
      .then(module => module.init())
      .catch(err => console.error('加载失败', err));
    
  3. 现代框架最佳实践:

    • React:React.lazy + Suspense
    • Vue:异步组件
    • Angular:路由懒加载

最终性能公式:

页面响应速度 = (关键资源大小/网络速度) + 最长任务时间

每次网络请求都是潜在的阻塞点,每毫秒执行时间都会影响用户体验。

转自https://juejin.cn/post/7523037165254934571


该文章在 2025/7/7 11:14:21 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved