script 标签上有那些属性,分别作用是啥?

663 阅读3分钟

每个前端开发者都在使用 <script> 标签,但90%的人只掌握了它20%的能力。本文将揭示那些能显著提升页面加载速度的隐藏属性!

一、基础属性:必备技能

1. src - 脚本来源定位器

作用:指定外部JS文件路径
案例:引入第三方库

<script src="https://cdn.example.com/vue@3.4.0.global.js"></script>

原理:浏览器会发起GET请求获取资源并执行
对比

  • 行内脚本 <script>console.log('hi')</script> 适用于小段代码
  • 外部脚本更易缓存且复用率高

2. type - 脚本类型定义

作用:声明脚本MIME类型或模块类型
高级用法

<!-- ES模块(现代浏览器) -->
<script type="module" src="main.js"></script>

<!-- 旧式兼容 -->
<script nomodule src="legacy.js"></script>

动态类型案例

<script type="application/json" id="config">
  {"theme": "dark", "apiBase": "/v2"}
</script>
// 前端获取配置
const config = JSON.parse(document.getElementById('config').textContent);

二、加载控制:性能关键属性

1. defer - 异步延迟执行

作用:不阻塞HTML解析,在DOMContentLoaded前按顺序执行

优化案例

<head>
  <script src="analytics.js" defer></script>
  <script src="vender.js" defer></script>
  <script src="app.js" defer></script>
</head>

执行顺序
analytics.jsvender.jsapp.js(即使下载完成顺序不同)

2. async - 异步立即执行

作用:下载不阻塞解析,下载完成立即执行(无序)

适用场景:独立第三方脚本

<!-- 广告/统计脚本 -->
<script async src="https://www.googletagmanager.com/gtag/js"></script>

对比表:defer vs async

特性deferasync
执行时机DOM解析后,DOMContentLoaded下载完成立即执行
顺序保证按声明顺序执行不保证顺序
适用场景主业务脚本独立第三方脚本
是否阻塞解析下载时不阻塞,执行时阻塞

三、安全增强:保护你的应用

1. integrity - 资源完整性校验

作用:防止CDN资源被篡改(Subresource Integrity)

用法

<script 
  src="https://cdn.example.com/react.production.min.js"
  integrity="sha384-9aVv5e0d3dJ7A00a4F7FZl2M4G4hqiqZ9M0Qb5thzP5Z"
  crossorigin="anonymous">
</script>

原理
浏览器会计算脚本SHA384哈希值并校验是否匹配
不匹配则拒绝执行

2. nonce - 内容安全策略

作用:防止XSS攻击,配合CSP使用

案例

# HTTP Header
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
  // 内联脚本必须匹配nonce值才能执行
</script>

3. crossorigin - 跨域控制

作用:控制跨域脚本的请求模式和凭据发送

作用
anonymous跨域请求不带Cookie
use-credentials携带Cookie(需Access-Control-Allow-Credentials)

错误捕获案例

<script 
  src="https://another-domain.com/error-monitor.js" 
  crossorigin="anonymous"
  onerror="fallback()">
</script>

四、前沿实战技巧

1. 动态脚本加载

// SEO友好方案:先显示核心内容,后加载非关键脚本
window.addEventListener('load', () => {
  const script = document.createElement('script');
  script.src = 'lazy-analytics.js';
  script.setAttribute('async', '');
  document.body.appendChild(script);
});

2. 现代化模块加载器

<!-- 现代浏览器加载ESM -->
<script type="module" src="modern.js"></script>

<!-- 老旧浏览器回退方案 -->
<script nomodule src="legacy.js"></script>

3. 预加载优化

结合<link rel="preload">提升性能:

<head>
  <!-- 提前加载不阻塞渲染 -->
  <link rel="preload" href="critical.js" as="script">
</head>
<body>
  <!-- 实际使用 -->
  <script src="critical.js" defer></script>
</body>

效果对比
普通加载:⬛⬛⬜⬜ JS下载中...
预加载:⬛⬛⬛⬛ JS已准备就绪


五、其他

1. 脚本阻塞渲染怎么办?

症状:页面白屏时间长
优化

<!-- 错误 -->
<script src="heavy-script.js"></script> <!-- 阻塞! -->

<!-- 正确 -->
<script src="heavy-script.js" defer></script>
<!-- 或 -->
<script src="heavy-script.js" async></script>

2. 如何避免重复加载?

// 动态脚本加载防重复
if (!window.myLibraryLoaded) {
  const script = document.createElement('script');
  script.src = 'library.js';
  document.head.appendChild(script);
  window.myLibraryLoaded = true;
}

3. 脚本加载失败处理

<script src="essential.js" onerror="handleScriptError()"></script>
function handleScriptError() {
  // 1. 加载备用CDN
  // 2. 降级到静态版本
  // 3. 显示用户通知
}

🌟 最佳实践总结

  1. 核心脚本:使用defer保证顺序不阻塞

    <script src="framework.js" defer></script>
    
  2. 独立脚本:使用async加速加载

    <script async src="analytics.js"></script>
    
  3. 动态资源:结合preload预加载

    <link rel="preload" href="dynamic-module.js" as="script">
    
  4. 安全防护:必须添加integrity校验

    <script integrity="sha384-..." src="https://cdn.com/lib.js"></script>
    
  5. 现代兼容:模块化方案

    <script type="module" src="app.mjs"></script>
    <script nomodule src="fallback.js"></script>
    

首屏关键脚本defer,非关键脚本动态加载,第三方用async,CDN资源必加integrity