每个前端开发者都在使用
<script>
标签,但90%的人只掌握了它20%的能力。本文将揭示那些能显著提升页面加载速度的隐藏属性!
一、基础属性:必备技能
1. src
- 脚本来源定位器
作用 :指定外部JS文件路径
案例:引入第三方库
html
<script src="https://cdn.example.com/vue@3.4.0.global.js"></script>
原理 :浏览器会发起GET请求获取资源并执行
对比:
- 行内脚本
<script>console.log('hi')</script>
适用于小段代码 - 外部脚本更易缓存且复用率高
2. type
- 脚本类型定义
作用 :声明脚本MIME类型或模块类型
高级用法:
html
<!-- ES模块(现代浏览器) -->
<script type="module" src="main.js"></script>
<!-- 旧式兼容 -->
<script nomodule src="legacy.js"></script>
动态类型案例:
html
<script type="application/json" id="config">
{"theme": "dark", "apiBase": "/v2"}
</script>
js
// 前端获取配置
const config = JSON.parse(document.getElementById('config').textContent);
二、加载控制:性能关键属性
1. defer
- 异步延迟执行
作用 :不阻塞HTML解析,在DOMContentLoaded
前按顺序执行
优化案例:
html
<head>
<script src="analytics.js" defer></script>
<script src="vender.js" defer></script>
<script src="app.js" defer></script>
</head>
执行顺序 :
analytics.js
→ vender.js
→ app.js
(即使下载完成顺序不同)
2. async
- 异步立即执行
作用:下载不阻塞解析,下载完成立即执行(无序)
适用场景:独立第三方脚本
html
<!-- 广告/统计脚本 -->
<script async src="https://www.googletagmanager.com/gtag/js"></script>
对比表:defer
vs async
特性 | defer |
async |
---|---|---|
执行时机 | DOM解析后,DOMContentLoaded 前 |
下载完成立即执行 |
顺序保证 | 按声明顺序执行 | 不保证顺序 |
适用场景 | 主业务脚本 | 独立第三方脚本 |
是否阻塞解析 | 否 | 下载时不阻塞,执行时阻塞 |
三、安全增强:保护你的应用
1. integrity
- 资源完整性校验
作用:防止CDN资源被篡改(Subresource Integrity)
用法:
html
<script
src="https://cdn.example.com/react.production.min.js"
integrity="sha384-9aVv5e0d3dJ7A00a4F7FZl2M4G4hqiqZ9M0Qb5thzP5Z"
crossorigin="anonymous">
</script>
原理 :
浏览器会计算脚本SHA384哈希值并校验是否匹配
不匹配则拒绝执行
2. nonce
- 内容安全策略
作用:防止XSS攻击,配合CSP使用
案例:
http
# HTTP Header
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
html
<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
// 内联脚本必须匹配nonce值才能执行
</script>
3. crossorigin
- 跨域控制
作用:控制跨域脚本的请求模式和凭据发送
值 | 作用 |
---|---|
anonymous |
跨域请求不带Cookie |
use-credentials |
携带Cookie(需Access-Control-Allow-Credentials) |
错误捕获案例:
html
<script
src="https://another-domain.com/error-monitor.js"
crossorigin="anonymous"
onerror="fallback()">
</script>
四、前沿实战技巧
1. 动态脚本加载
javascript
// SEO友好方案:先显示核心内容,后加载非关键脚本
window.addEventListener('load', () => {
const script = document.createElement('script');
script.src = 'lazy-analytics.js';
script.setAttribute('async', '');
document.body.appendChild(script);
});
2. 现代化模块加载器
html
<!-- 现代浏览器加载ESM -->
<script type="module" src="modern.js"></script>
<!-- 老旧浏览器回退方案 -->
<script nomodule src="legacy.js"></script>
3. 预加载优化
结合<link rel="preload">
提升性能:
html
<head>
<!-- 提前加载不阻塞渲染 -->
<link rel="preload" href="critical.js" as="script">
</head>
<body>
<!-- 实际使用 -->
<script src="critical.js" defer></script>
</body>
效果对比 :
普通加载:⬛⬛⬜⬜ JS下载中...
预加载:⬛⬛⬛⬛ JS已准备就绪
五、其他
1. 脚本阻塞渲染怎么办?
症状 :页面白屏时间长
优化:
html
<!-- 错误 -->
<script src="heavy-script.js"></script> <!-- 阻塞! -->
<!-- 正确 -->
<script src="heavy-script.js" defer></script>
<!-- 或 -->
<script src="heavy-script.js" async></script>
2. 如何避免重复加载?
javascript
// 动态脚本加载防重复
if (!window.myLibraryLoaded) {
const script = document.createElement('script');
script.src = 'library.js';
document.head.appendChild(script);
window.myLibraryLoaded = true;
}
3. 脚本加载失败处理
html
<script src="essential.js" onerror="handleScriptError()"></script>
javascript
function handleScriptError() {
// 1. 加载备用CDN
// 2. 降级到静态版本
// 3. 显示用户通知
}
🌟 最佳实践总结
-
核心脚本 :使用
defer
保证顺序不阻塞html<script src="framework.js" defer></script>
-
独立脚本 :使用
async
加速加载html<script async src="analytics.js"></script>
-
动态资源 :结合
preload
预加载html<link rel="preload" href="dynamic-module.js" as="script">
-
安全防护 :必须添加
integrity
校验html<script integrity="sha384-..." src="https://cdn.com/lib.js"></script>
-
现代兼容:模块化方案
html<script type="module" src="app.mjs"></script> <script nomodule src="fallback.js"></script>
首屏关键脚本
defer
,非关键脚本动态加载,第三方用async
,CDN资源必加integrity