在这里插入图片描述

前端性能优化必看:preload和prefetch让页面加载快人一步(附避坑指南)

前端性能优化必看:preload和prefetch让页面加载快人一步(附避坑指南)

先说个扎心的事儿

你家的网站首屏加载是不是慢到用户想砸手机?明明资源都压缩了、图片也懒加载了、CDN也上了,为啥还是卡成PPT?用户在那盯着白屏发呆三秒钟,心里早就把你祖宗十八代问候了个遍,然后手指一滑,拜拜了您嘞,转化率直接归零。

我跟你说,这事儿真不能全怪网络。浏览器其实早就给了你加速神器,只是你没用对,或者说,你根本不知道它的存在。今天就把这个压箱底的干货掏出来跟大家唠唠——preloadprefetch这对卧龙凤雏,用好了能让你的页面加载快人一步,用错了……嘿嘿,那画面太美我不敢看。

说实话,我第一次听说这俩API的时候,心里也是懵逼的:这不都是预加载吗?有啥区别?后来踩了一堆坑,被测试小姐姐追着骂,被产品经理质疑能力,才慢慢琢磨出门道。现在就把这些血泪经验分享出来,希望能帮你少走点弯路。

浏览器加载资源那点门道

要搞懂preloadprefetch,咱得先聊聊浏览器是怎么加载资源的。这玩意儿就跟排队打饭一样,讲究个先来后到、尊卑有序。

Chrome内部给资源排优先级的骚操作

Chrome内核(Blink)给资源分了五个优先级档次,从HighestLowest,跟王者荣耀的段位似的:

  • Highest:HTML文档本身,这是祖宗,没它页面都渲染不出来
  • High:CSS样式表,没有CSS页面就是一团乱麻,用户看了直接崩溃
  • Medium:普通的JS脚本、图片这些
  • Low:异步加载的脚本、预加载的资源
  • Lowestprefetch预加载的资源,基本就是"有空再搞"的意思

浏览器会根据资源类型、位置、属性自动分配优先级。比如放在<head>里的同步JS就是High,放在</body>前面的就是Medium,加了asyncdefer的就更低。

HTML和CSS为啥永远站在鄙视链顶端

你想啊,HTML是页面的骨架,CSS是衣服,JS是肌肉。骨架和衣服都没有,你光有一身肌肉(JS),那不就是解剖课上的标本吗?吓人不说,根本没法看。所以浏览器会优先保证HTML和CSS的下载和解析,这是渲染阻塞资源,必须等它们到位才能开始画页面。

这里有个关键概念叫关键渲染路径(Critical Rendering Path)。浏览器收到HTML后开始解析,遇到CSS就发请求,同时继续解析HTML。等CSS回来了,构建CSSOM,和DOM一起合成渲染树,然后布局、绘制。如果CSS卡住了,后面的步骤全得等着。

JS脚本根据位置不同待遇天差地别

JS这玩意儿特别矫情。默认情况下,浏览器遇到<script>标签就会停下来下载并执行,因为JS可能会修改DOM和CSSOM。这就是所谓的脚本阻塞

<!-- 这种写法会阻塞渲染,优先级 High -->
<script src="critical.js"></script>

<!-- 放在底部,优先级 Medium,不会阻塞首屏 -->
<script src="non-critical.js"></script>

<!-- async 异步下载,下载完立即执行,优先级 Low -->
<script async src="analytics.js"></script>

<!-- defer 异步下载,等HTML解析完再执行,优先级 Low -->
<script defer src="app.js"></script>

所以老前端都知道,非关键的JS要放底部,或者加async/defer。但有时候有些JS就是关键资源,比如埋点库、错误监控,这时候就得用preload来提前加载,避免阻塞。

一张图看懂浏览器加载队列的内心戏

想象一下浏览器内部有个资源调度中心,就像机场塔台指挥飞机起降:

  1. HTML文档最先起飞(Highest)
  2. CSS紧随其后(High)
  3. 首屏需要的字体、关键JS开始排队(High/Medium)
  4. 图片资源根据是否在视口内决定优先级(Medium/Low)
  5. prefetch的资源被扔到了"候补席",等前面没活儿了再说(Lowest)

preload的作用就是让你可以手动调整这个队列,把某个资源从经济舱升级到头等舱。而prefetch则是给下一趟航班占个座,这趟航班先不管它。

preload到底是个啥玩意儿

官方说法叫资源提示符(Resource Hint),咱说人话就是插队券。你告诉浏览器:“这个资源我现在马上就要用,你给我插队到最前面,别的资源先靠边站。”

告诉浏览器这个资源我现在马上就要用

preload的设计初衷是解决** late-discovered resources **的问题。啥意思呢?就是有些资源浏览器一开始不知道需要它,等解析到某个阶段才发现:"哎呀,原来还需要这个字体/图片/脚本!"这时候才去下载,就耽误了时间。

最典型的例子就是自定义字体。CSS里用@font-face声明了字体,但浏览器解析CSS的时候只是记下了这个声明,等到实际渲染文本时才发现:"卧槽,这个字要用WebFont,我得去下载!"这时候用户已经看到文字了,然后文字突然一闪变成自定义字体,这就是FOIT(Flash of Invisible Text)FOUT(Flash of Unstyled Text),体验极差。

preload可以提前把字体下载好:

<!-- 提前加载字体文件,避免字体闪烁 -->
<link rel="preload" href="/fonts/awesome-font.woff2" as="font" type="font/woff2" crossorigin>

注意那个crossorigin属性,字体资源是跨域的,必须加这个,不然浏览器不会用预加载的字体,还是会重新下载。

优先级直接拉到最高不给其他资源留面子

当你用preload时,浏览器会把对应资源的优先级提升到High甚至Highest,跟CSS一个级别。这意味着它会抢占带宽,其他资源得先等等。

这既是优点也是缺点。优点是真的快,缺点是用多了会挤占其他资源的带宽,反而拖慢整体加载。所以preload要精准打击,只用来加载真正关键的资源。

加载完放内存缓存里当前页面随取随用

preload加载的资源会放在**内存缓存(Memory Cache)**里,这个页面内随取随用,速度极快。而且因为是预加载,浏览器会提前建立连接、解析DNS,真正用到的时候直接拿,省去了网络往返的时间。

必须配合as属性不然浏览器会重复下载白忙活

这里有个大坑!preload必须配合as属性使用,告诉浏览器这个资源是什么类型。可能的值包括:

  • script:JavaScript文件
  • style:CSS文件
  • font:字体文件
  • image:图片
  • fetch:XHR或Fetch请求
  • document:HTML文档(用于iframe)

为啥必须写as?因为浏览器要根据资源类型设置正确的请求头、优先级、CSP策略等。如果你不写as,或者写错了,浏览器下载了也不会用,等真正需要的时候会重新下载一遍,白忙活一场。

<!-- 正确写法 -->
<link rel="preload" href="/js/app.js" as="script">

<!-- 错误写法 - 不写as -->
<link rel="preload" href="/js/app.js">

<!-- 错误写法 - as写错 -->
<link rel="preload" href="/js/app.js" as="style"> <!-- 浏览器会以为是CSS,不会执行JS -->

还有个type属性用于指定MIME类型,如果浏览器不支持这种类型就不会下载,用来做渐进增强:

<!-- 只有支持module的浏览器才会预加载 -->
<link rel="preload" href="/js/app.mjs" as="script" type="module">

prefetch又是哪路神仙

如果说preload是个急性子,prefetch就是个佛系青年。它的意思很明确:“这个资源现在不用,但等会儿可能要,你先准备着,有空的时候下载一下,没空就算了。”

跟preload比起来就是个佛系青年

prefetch的优先级是Lowest,浏览器只有在当前页面的关键资源都下载完了,带宽空闲的时候,才会去下载prefetch的资源。如果用户网络不好,或者很快跳走了,可能根本就不会下载。

这听起来好像很鸡肋?其实不然。它的设计目标就是为下一页预加载资源,提升后续导航的体验。

意思是这个资源现在不用但等会儿可能要

典型的使用场景是单页应用(SPA)的路由切换。用户在首页,很可能下一步会跳转到详情页。你可以prefetch详情页需要的代码块,等用户真的点击时,资源已经缓存好了,切换秒开。

<!-- 预加载下一页可能需要的资源 -->
<link rel="prefetch" href="/js/detail-page.js">
<link rel="prefetch" href="/api/product-detail.json">

优先级降到最低等浏览器闲了再慢慢下

因为优先级低,prefetch不会跟当前页面的资源抢带宽,不会影响首屏加载。这是它和preload最大的区别之一。

适合预加载下一页可能用到的东西

除了SPA,多页应用(MPA)也能用。比如电商网站,用户在商品列表页,你可以prefetch商品详情页的关键资源。但要注意,别一股脑把所有链接对应的页面都prefetch,那会把用户的流量吃光,而且浏览器有并发限制,太多反而一个都下不下来。

缓存机制跟preload不一样跨页面也能用

prefetch的资源会放在**HTTP缓存(Disk Cache)**里,跨页面也能用。用户从A页跳到B页,如果B页需要的资源在A页已经prefetch过了,直接从缓存拿,速度飞快。

preload的资源主要在内存缓存里,页面关了就没,而且一般不跨页面共享(除非是用Service Worker做了特殊处理)。

这俩兄弟的区别得拎清楚

说实话,我刚学的时候经常搞混这俩,以为都是预加载,随便用哪个都行。后来吃了亏才明白,它们的差异可大了去了。

使用场景完全不同别搞混了闹笑话

特性 preload prefetch
目标 当前页面 下一页/未来页面
优先级 High/Highest Lowest
缓存位置 内存缓存 磁盘缓存
是否阻塞 可能阻塞渲染(如果滥用) 不阻塞
跨页面 一般不共享 可以共享

preload管当前页面prefetch管未来页面

这是最根本的区别。preload解决的是"我现在就需要,但浏览器发现得晚"的问题。prefetch解决的是"我一会儿可能需要,先准备着"的问题。

优先级一个天一个地带宽分配差很多

preload会抢占带宽,所以要慎用。prefetch是"捡漏"的,有剩余带宽才下,不会影响当前页面。

缓存行为也不一样复用效率有讲究

preload在内存里,快但生命周期短;prefetch在磁盘里,慢点但持久。如果你预加载的资源是下一页用的,用prefetch更合适,因为用户可能过一会儿才跳转,内存缓存可能早被清掉了。

用错了不仅没加速还可能拖慢页面

我见过有人把页面上所有图片都用preload,结果首屏加载反而更慢了,因为带宽被这些图片占满,CSS和JS都在排队。这就是典型的滥用。

还有人用prefetch来加载当前页面需要的资源,结果浏览器优先级太低,等到用的时候还没下载完,白预加载一场。

实际开发中咋用才不翻车

理论讲了一堆,来点实战的。这些都是我在项目里真实用过的方案,有成功的也有踩坑的,分享出来供参考。

关键CSS文件用preload避免渲染阻塞

如果你的CSS是动态加载的(比如通过JS判断加载不同主题),或者CSS文件特别大,可以用preload提前加载:

<!-- 提前加载关键CSS -->
<link rel="preload" href="/css/critical.css" as="style" onload="this.rel='stylesheet'">

<!-- 兜底:如果JS禁用,用noscript -->
<noscript><link rel="stylesheet" href="/css/critical.css"></noscript>

这里用了个小技巧:onload="this.rel='stylesheet'",这样预加载完成后自动应用样式,不会重复下载。但要注意,这种写法在Safari上有兼容性问题,需要polyfill或者直接用传统的<link rel="stylesheet">

更稳妥的做法是直接用preload提示,然后正常引入CSS:

<link rel="preload" href="/css/main.css" as="style">
<link rel="stylesheet" href="/css/main.css">

浏览器会聪明地复用预加载的CSS,不会下载两次。

自定义字体预加载告别字体闪烁的尴尬

字体预加载是最常见的preload使用场景。前面说过,字体是late-discovered resource,不用preload就会出现闪烁。

<!-- 预加载自定义字体 -->
<link rel="preload" href="/fonts/Inter-Regular.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/Inter-Bold.woff2" as="font" type="font/woff2" crossorigin>

<style>
  @font-face {
    font-family: 'Inter';
    src: url('/fonts/Inter-Regular.woff2') format('woff2');
    font-weight: 400;
    font-display: swap; /* 配合font-display使用 */
  }
  @font-face {
    font-family: 'Inter';
    src: url('/fonts/Inter-Bold.woff2') format('woff2');
    font-weight: 700;
    font-display: swap;
  }
  
  body {
    font-family: 'Inter', sans-serif;
  }
</style>

注意几点:

  1. 必须加crossorigin,即使是同域字体(因为字体请求默认是anonymous CORS模式)
  2. 只预加载关键字体,比如Regular和Bold,Light、Italic这些非关键的字重可以不管
  3. 配合font-display: swap,让浏览器先用系统字体渲染,等自定义字体来了再换,避免 invisible text

首屏图片该预加载就别懒加载了

懒加载(lazy loading)是个好技术,但首屏图片不能懒加载,因为用户一进来就要看到。这些图片可以用preload提前加载:

<!-- 首屏Hero图片预加载 -->
<link rel="preload" href="/images/hero-banner.webp" as="image" type="image/webp" imagesrcset="/images/hero-banner-400.webp 400w, /images/hero-banner-800.webp 800w" imagesizes="100vw">

<!-- 响应式图片预加载(Chrome 73+支持) -->
<link rel="preload" href="/images/hero.png" as="image" imagesrcset="/images/hero-400.png 400w, /images/hero-800.png 800w" imagesizes="(max-width: 600px) 400px, 800px">

这里用了imagesrcsetimagesizes,让浏览器根据屏幕大小预加载合适的图片尺寸,避免浪费带宽。

但要注意,不要预加载太多图片。一般来说,首屏只有1-2张关键图片需要预加载,其他的用懒加载。

路由跳转的下一个页面资源可以prefetch

在SPA里,结合路由库可以做智能预加载。比如用React Router:

// 路由配置
const routes = [
  {
    path: '/',
    component: Home,
    // 首页组件本身可能需要预加载其他资源
  },
  {
    path: '/product/:id',
    component: () => import('./ProductDetail'), // 动态导入
    prefetch: true // 标记可预加载
  }
];

// 在Link组件里做hover预加载
const SmartLink = ({ to, children }) => {
  const handleMouseEnter = () => {
    // 鼠标放上去就开始预加载
    const route = routes.find(r => r.path === to);
    if (route && route.component && typeof route.component === 'function') {
      route.component(); // 执行动态导入
    }
    
    // 也可以prefetch API数据
    if (to.startsWith('/product/')) {
      const link = document.createElement('link');
      link.rel = 'prefetch';
      link.href = `/api/product/${to.split('/').pop()}`;
      document.head.appendChild(link);
    }
  };

  return (
    <Link to={to} onMouseEnter={handleMouseEnter}>
      {children}
    </Link>
  );
};

这个思路是预测用户行为。鼠标hover到链接上时,有很大概率用户会点击,这时候开始预加载,等真的点击时资源已经准备好了。从hover到click通常有几百毫秒的时间,足够下载很多资源了。

SPA应用里配合代码分割效果更香

现代前端工具(Webpack、Vite、Rollup)都支持代码分割,配合import()动态导入和prefetch,可以实现路由级别的按需加载+预加载:

// Webpack魔法注释实现prefetch
const AdminDashboard = () => import(
  /* webpackChunkName: "admin" */
  /* webpackPrefetch: true */  // 告诉Webpack生成prefetch标签
  './AdminDashboard.vue'
);

// 或者手动控制
const UserProfile = () => import('./UserProfile.vue');

// 在用户登录后,预加载管理后台(因为登录后很可能有权限进后台)
if (user.isLoggedIn && user.hasAdminRole) {
  // 动态创建prefetch link
  const link = document.createElement('link');
  link.rel = 'prefetch';
  link.href = '/js/admin-dashboard.js'; // 根据实际chunk文件名调整
  document.head.appendChild(link);
}

Webpack的webpackPrefetch: true会自动在head里插入<link rel="prefetch">,省心省力。

视频海报图提前加载用户体验直接拉满

如果页面有视频,海报图(poster)是用户首先看到的,可以用preload

<!-- 预加载视频海报 -->
<link rel="preload" href="/images/video-poster.jpg" as="image">

<video poster="/images/video-poster.jpg" controls preload="none">
  <source src="/video/demo.mp4" type="video/mp4">
</video>

注意视频的preload属性默认是auto,会预加载视频数据,如果不需要可以设为nonemetadata,节省流量。

踩过的坑都在这儿了别重复造轮子

说了这么多好处,也得说说坑。这些都是我血泪的教训,希望你别重蹈覆辙。

preload忘记写as属性导致资源下载两次

这个前面强调过了,但太常见了,再啰嗦一遍。有一次我预加载一个JSON文件(用于Web Worker),写了:

<!-- 错误!JSON应该用fetch -->
<link rel="preload" href="/data/config.json">

结果浏览器下载了一遍,然后Fetch API又下载了一遍,因为浏览器不知道这个资源是干嘛用的,没放到对应的缓存池里。正确的写法是:

<!-- 正确:用as="fetch" -->
<link rel="preload" href="/data/config.json" as="fetch" crossorigin>

然后在JS里:

fetch('/data/config.json')
  .then(res => res.json())
  .then(data => {
    // 浏览器会复用预加载的响应
  });

滥用preload把不该优先的资源也插队

我曾经把页面上所有字体(Regular、Light、Bold、Italic、Bold Italic,共5个文件)都用preload,结果首屏加载时间从1.2秒涨到了2.5秒,因为带宽被字体占满了,CSS和JS都在排队等。

后来只预加载了Regular和Bold,其他的让浏览器正常加载,首屏时间降回1.3秒。记住:只预加载关键资源

prefetch用太多占用带宽反而拖慢当前页

虽然prefetch优先级低,但如果你prefetch了几十个资源,浏览器还是会尝试下载,这会占用TCP连接数、消耗用户流量,而且可能挤占当前页面的非关键资源(比如图片)的带宽。

建议一个页面prefetch的资源不超过5-10个,而且要是高概率会用到的。

移动端网络环境下要更谨慎使用

移动端网络不稳定,用户可能用的是2G/3G或者流量紧张。这时候prefetch可能浪费用户流量,而且下载速度慢,还没下完用户就跳走了。

可以用Network Information API检测网络状况,智能决定是否prefetch:

// 检测网络状况
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;

if (connection) {
  // effectiveType可能是 '4g', '3g', '2g', 'slow-2g'
  if (connection.effectiveType === '4g' && !connection.saveData) {
    // 只有4G且未开启省流量模式时才prefetch
    const link = document.createElement('link');
    link.rel = 'prefetch';
    link.href = '/js/next-page.js';
    document.head.appendChild(link);
  }
}

跟懒加载配合使用时机没把握好

有个常见误区:给懒加载的图片加preload。这逻辑上是矛盾的——懒加载是为了"不需要的时候不加载",preload是为了"提前加载"。如果你预加载了懒加载的图片,那还懒加载个啥?

正确的做法是:首屏关键图片用preload,非首屏图片用懒加载

<!-- 首屏关键图片:preload + 不懒加载 -->
<link rel="preload" href="/images/hero.jpg" as="image">
<img src="/images/hero.jpg" alt="Hero" width="800" height="600">

<!-- 非首屏图片:懒加载,不要preload -->
<img data-src="/images/below-fold.jpg" loading="lazy" alt="Below fold" width="400" height="300">

开发者工具里看不到prefetch缓存别慌

有时候你在Network面板里看不到prefetch的请求,或者看到状态是pending,这是正常的。因为prefetch优先级太低,可能被推迟执行,或者被浏览器取消了(比如用户很快跳走了)。

想看prefetch是否生效,可以在Application面板的Cache Storage或Local Storage里查看,或者看后续页面加载时这些资源是否从disk cache读取。

排查问题的思路得有一套

优化完了得验证效果,出了问题得会排查。下面是我常用的调试方法。

打开Chrome开发者工具Network面板

这是最基本的操作。打开DevTools,切换到Network面板,勾选"Disable cache"(禁用缓存)来模拟首次访问,或者保持不勾选来看缓存效果。

看Priority列确认资源优先级对不对

在Network面板的表头右键,勾选"Priority"列,可以看到每个资源的优先级:

  • 如果你用了preload,应该看到对应资源的优先级是High
  • 如果是prefetch,应该是Lowest
  • 如果不对,检查relas属性是否写对

Waterfall瀑布图能看出加载时序有没有问题

看Waterfall列,资源是从上到下发请求的。关键资源(CSS、关键JS)应该尽早开始下载,如果它们开始得很晚,说明被其他资源阻塞了,可能需要调整顺序或用preload提升优先级。

内存缓存和磁盘缓存的区别要分清楚

在Size列可以看到缓存类型:

  • (memory cache):内存缓存,极快,页面关闭即消失
  • (disk cache):磁盘缓存,较快,跨页面可用
  • (prefetch cache):Chrome对prefetch资源的特殊标记,其实也是disk cache的一种

如果你preload了一个资源,但看到它是从disk cache读取的,说明预加载没生效,可能是as属性写错了。

Lighthouse跑分能给你优化建议

Lighthouse是Google的自动化测试工具,在DevTools的Lighthouse面板就能跑。它会检测你是否正确使用了preloadprefetch,并给出建议。

常见的相关审计项:

  • Preload key requests:提示你应该预加载的关键资源
  • Preload Largest Contentful Paint image:提示预加载LCP图片
  • Avoid enormous network payloads:警告你预加载了太多资源

Performance面板记录加载过程慢慢分析

对于复杂的性能问题,用Performance面板记录页面加载过程,可以看到:

  • 每个资源的精确加载时间
  • 主线程的阻塞情况
  • 渲染的具体时间点(FP、FCP、LCP等)

结合这些信息,可以判断preload是否真的起到了加速作用,还是只是增加了竞争。

几个让性能起飞的小技巧

最后分享一些进阶技巧,都是我实战中总结的。

关键路径资源尽量用preload提前招呼

关键渲染路径上的资源,如果不在HTML最开始就引入,都可以用preload。比如:

<head>
  <!-- 1. 预加载关键CSS -->
  <link rel="preload" href="/css/critical.css" as="style">
  
  <!-- 2. 预加载关键字体 -->
  <link rel="preload" href="/fonts/main.woff2" as="font" crossorigin>
  
  <!-- 3. 预加载首屏关键JS(比如埋点库) -->
  <link rel="preload" href="/js/monitor.js" as="script">
  
  <!-- 4. 正常引入CSS -->
  <link rel="stylesheet" href="/css/critical.css">
</head>

非关键资源该defer就defer别堵着渲染

不要所有JS都塞在<head>里,非关键的(比如统计代码、广告脚本、社交分享按钮)都放底部或加defer

<!-- 关键JS,可能用preload -->
<script src="/js/app.js" defer></script>

<!-- 非关键JS,放底部 -->
<script src="/js/analytics.js" async></script>
<script src="/js/chat-widget.js" defer></script>

图片根据重要性决定preload还是懒加载

制定一个图片加载策略:

  • LCP图片(最大内容绘制,通常是首屏大图):preload + 优先加载
  • 首屏其他图片:正常加载,不用preload也不用懒加载
  • 非首屏图片loading="lazy"懒加载
  • 可能很快要看的图片(比如轮播图的下一张):prefetch或提前用JS加载
<!-- LCP图片预加载 -->
<link rel="preload" as="image" href="/images/hero.webp">

<!-- 首屏普通图片 -->
<img src="/images/logo.png" alt="Logo" width="200" height="50">

<!-- 非首屏懒加载 -->
<img data-src="/images/footer.png" loading="lazy" alt="Footer" width="400" height="200">

第三方脚本能异步就别同步加载

第三方脚本(Google Analytics、Facebook Pixel、客服插件等)通常很慢,而且不受你控制。一定要用异步加载,避免阻塞:

<!-- 异步加载Google Analytics -->
<script>
  // 动态创建script标签,避免阻塞
  window.gaLoaded = new Promise((resolve) => {
    const script = document.createElement('script');
    script.src = 'https://www.google-analytics.com/analytics.js';
    script.async = true;
    script.onload = resolve;
    document.head.appendChild(script);
  });
</script>

如果第三方脚本支持asyncdefer属性,直接用:

<script src="https://third-party.com/script.js" async defer></script>

结合preconnect提前建立连接更省时

preconnect是另一个资源提示符,用来提前建立DNS查询、TCP连接、TLS握手,适用于那些你确定会访问的第三方域名:

<!-- 提前建立Google Fonts的连接 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

<!-- 然后正常引入字体CSS -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">

这样等浏览器解析到CSS需要下载字体时,连接已经建立好了,省去了几百毫秒的连接时间。

preconnectpreload可以配合使用:

<!-- 1. 先建立连接 -->
<link rel="preconnect" href="https://cdn.example.com">

<!-- 2. 预加载关键资源 -->
<link rel="preload" href="https://cdn.example.com/critical.js" as="script">

DNS预解析dns-prefetch小细节大作用

如果有些域名你不确定是否会访问,或者只是可能访问,用dns-prefetch做DNS预解析,比preconnect更轻量:

<!-- 预解析DNS -->
<link rel="dns-prefetch" href="https://api.example.com">
<link rel="dns-prefetch" href="https://cdn.example.com">
<link rel="dns-prefetch" href="https://images.example.com">

这样等真正请求这些域名时,DNS已经解析好了,节省几十到几百毫秒。

preconnectdns-prefetch的关系:

  • preconnect = DNS + TCP + TLS, heavier but faster when used
  • dns-prefetch = DNS only, lighter but less gain

建议:关键第三方域名用preconnect,其他可能用到的用dns-prefetch

最后唠两句

性能优化这事儿没有银弹,别指望一招鲜吃遍天。preloadprefetch只是工具箱里的两件工具,用对了是神器,用错了就是累赘。

我见过的最离谱的案例,有人给页面上的所有外链CSS和JS都加了preload,结果首屏时间增加了3秒,因为浏览器带宽被这些预加载占满,真正关键的资源反而在排队。这就是典型的"优化过度"。

记住几个原则:

  1. 测了再优化:先用Lighthouse、WebPageTest等工具测出瓶颈,针对性优化
  2. 少即是多:预加载的资源越少越好,只选最关键的
  3. 移动端优先:移动端网络差,更要谨慎使用,做好降级方案
  4. 持续监控:性能优化不是一次性的,要持续监控,防止回归

多测多看,不瞎搞,线上出问题就尴尬了。下次面试被问到这个,你能侃侃而谈半小时,从浏览器原理讲到实战案例,从API细节讲到踩坑经验,面试官肯定对你刮目相看。

老板问你为啥网站变快了,你就把这篇文章甩给他,让他知道前端不是切图仔,是正经的技术活。当然,如果他看不懂,你就说:“用了一些浏览器底层的资源调度优化技术”,显得更高深莫测。

行了,就聊到这儿。该去改代码了,祝你页面加载飞快,用户永不流失,SEO排名暴涨,年终奖翻倍!

欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。

推荐:DTcode7的博客首页。
一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身农奴把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟!


专栏系列(点击解锁) 学习路线(点击解锁) 知识定位
《微信小程序相关博客》 持续更新中~ 结合微信官方原生框架、uniapp等小程序框架,记录请求、封装、tabbar、UI组件的学习记录和使用技巧等
《AIGC相关博客》 持续更新中~ AIGC、AI生产力工具的介绍,例如stable diffusion这种的AI绘画工具安装、使用、技巧等总结
《HTML网站开发相关》 《前端基础入门三大核心之html相关博客》 前端基础入门三大核心之html板块的内容,入坑前端或者辅助学习的必看知识
《前端基础入门三大核心之JS相关博客》 前端JS是JavaScript语言在网页开发中的应用,负责实现交互效果和动态内容。它与HTML和CSS并称前端三剑客,共同构建用户界面。
通过操作DOM元素、响应事件、发起网络请求等,JS使页面能够响应用户行为,实现数据动态展示和页面流畅跳转,是现代Web开发的核心
《前端基础入门三大核心之CSS相关博客》 介绍前端开发中遇到的CSS疑问和各种奇妙的CSS语法,同时收集精美的CSS效果代码,用来丰富你的web网页
《canvas绘图相关博客》 Canvas是HTML5中用于绘制图形的元素,通过JavaScript及其提供的绘图API,开发者可以在网页上绘制出各种复杂的图形、动画和图像效果。Canvas提供了高度的灵活性和控制力,使得前端绘图技术更加丰富和多样化
《Vue实战相关博客》 持续更新中~ 详细总结了常用UI库elementUI的使用技巧以及Vue的学习之旅
《python相关博客》 持续更新中~ Python,简洁易学的编程语言,强大到足以应对各种应用场景,是编程新手的理想选择,也是专业人士的得力工具
《sql数据库相关博客》 持续更新中~ SQL数据库:高效管理数据的利器,学会SQL,轻松驾驭结构化数据,解锁数据分析与挖掘的无限可能
《算法系列相关博客》 持续更新中~ 算法与数据结构学习总结,通过JS来编写处理复杂有趣的算法问题,提升你的技术思维
《IT信息技术相关博客》 持续更新中~ 作为信息化人员所需要掌握的底层技术,涉及软件开发、网络建设、系统维护等领域的知识
《信息化人员基础技能知识相关博客》 无论你是开发、产品、实施、经理,只要是从事信息化相关行业的人员,都应该掌握这些信息化的基础知识,可以不精通但是一定要了解,避免日常工作中贻笑大方
《信息化技能面试宝典相关博客》 涉及信息化相关工作基础知识和面试技巧,提升自我能力与面试通过率,扩展知识面
《前端开发习惯与小技巧相关博客》 持续更新中~ 罗列常用的开发工具使用技巧,如 Vscode快捷键操作、Git、CMD、游览器控制台等
《photoshop相关博客》 持续更新中~ 基础的PS学习记录,含括PPI与DPI、物理像素dp、逻辑像素dip、矢量图和位图以及帧动画等的学习总结
日常开发&办公&生产【实用工具】分享相关博客》 持续更新中~ 分享介绍各种开发中、工作中、个人生产以及学习上的工具,丰富阅历,给大家提供处理事情的更多角度,学习了解更多的便利工具,如Fiddler抓包、办公快捷键、虚拟机VMware等工具

吾辈才疏学浅,摹写之作,恐有瑕疵。望诸君海涵赐教。望轻喷,嘤嘤嘤

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。愿斯文对汝有所裨益,纵其简陋未及渊博,亦足以略尽绵薄之力。倘若尚存阙漏,敬请不吝斧正,俾便精进!

在这里插入图片描述

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐