【KO】前端面试七

117. 浏览器对队头阻塞有什么优化?【百度一面】

“队头阻塞”(Head-of-Line Blocking, HOLB)指因队列头部请求/数据包阻塞,导致后续请求/数据包无法处理的问题,常见于 HTTP/1.1 资源加载TCP 传输 场景,浏览器及协议层的优化手段如下:

一、针对 HTTP/1.1 资源加载的队头阻塞优化

HTTP/1.1 因“同一 TCP 连接中,请求需串行发送”,若前一个请求阻塞(如大文件加载慢、网络波动),后续请求会被卡在队列头部。浏览器主要通过以下方式缓解:

  1. 同域名并发连接限制

    • 浏览器为每个域名建立多个 TCP 连接(如 Chrome 默认为 6-8 个),将资源请求分散到不同连接中并行传输。例如,一个页面需加载 10 张图片,会分 2 批(每批 6 个)在不同连接中请求,避免单连接串行导致的阻塞。
    • 注意:并发连接数并非越多越好,过多会增加服务器压力,因此浏览器会限制上限。
  2. 资源域名分片(Domain Sharding)

    • 前端将静态资源(图片、CSS、JS)部署到多个子域名(如 img1.example.comimg2.example.com),每个子域名独立计算并发连接数。例如,用 3 个图片子域名,可获得 3×6=18 个并发连接,大幅提升资源加载并行度,避免单域名连接数不足导致的队头阻塞。
  3. 资源预加载与预连接

    • 预连接(Preconnect):通过 <link rel="preconnect" href="https://cdn.example.com"> 提前建立与目标域名的 TCP 连接(含 DNS 解析、TCP 握手、TLS 协商),后续请求直接复用连接,减少连接建立耗时,间接降低队头阻塞影响。
    • 预加载(Preload):通过 <link rel="preload" href="critical.js" as="script"> 优先加载关键资源(如首屏 JS、CSS),避免关键资源被非关键资源阻塞在队列中。
二、针对 TCP 传输层的队头阻塞优化(浏览器依赖协议升级)

TCP 协议本身存在队头阻塞(若某数据包丢失,后续数据包需在接收端缓存,等待丢失包重传后才能处理),浏览器无法直接修改 TCP 协议,但可通过 升级 HTTP 版本 间接规避:

  1. HTTP/2 多路复用(Multiplexing)

    • HTTP/2 基于“二进制帧”传输,同一 TCP 连接中可同时发送多个请求/响应(每个请求对应一个独立的“流”),流之间相互独立,不会因某一个流的阻塞影响其他流。例如,同一连接中,图片请求阻塞时,JS 请求仍可正常传输,从根本上解决了 HTTP/1.1 的队头阻塞问题。
  2. HTTP/3 基于 QUIC 协议

    • HTTP/3 放弃 TCP,改用基于 UDP 的 QUIC 协议。QUIC 同样支持多路复用,且每个流的数据包丢失仅影响当前流(TCP 是整个连接阻塞),进一步降低了传输层队头阻塞的影响,同时还优化了连接建立速度(0-RTT 握手)。
三、浏览器渲染层的间接优化(减少资源加载阻塞)
  • 异步加载 JS:通过 async/defer 属性让 JS 加载不阻塞 HTML 解析和渲染,避免因 JS 加载慢导致的页面渲染阻塞,间接减少“资源加载队头阻塞”对用户体验的影响(详见 116 题)。
  • CSS 优先级处理:浏览器会优先加载关键 CSS(首屏样式),非关键 CSS 延迟加载,避免因大体积 CSS 加载阻塞渲染,减少后续渲染任务的队头阻塞。

118. 如何实现一个图片懒加载(Lazy Loading)功能?【必会】

图片懒加载指“仅当图片进入或即将进入浏览器视口时,才加载图片资源”,核心目的是减少首屏请求数、节省带宽、提升页面加载速度。常见实现方案如下:

一、原生 loading="lazy" 属性(最简单,推荐优先使用)

现代浏览器(Chrome 77+、Firefox 75+、Safari 15.4+)原生支持图片懒加载,无需写 JS,只需给 <img> 标签添加 loading="lazy" 属性:

<!-- 原生懒加载:仅当图片进入视口时加载 -->
<img 
  src="placeholder.jpg"  <!-- 占位图(可选,如灰色背景图) -->
  data-src="real-image.jpg"  <!-- 真实图片地址(若用自定义逻辑,需配合 JS) -->
  loading="lazy" 
  alt="描述"
  <!-- 可选:设置预加载阈值,距离视口 200px 时开始加载 -->
  width="600" 
  height="400"  <!-- 必设:避免加载后页面重排 -->
>
  • 优点:零 JS 代码、浏览器原生优化、兼容性覆盖主流现代浏览器。
  • 缺点:不支持 IE 及老旧浏览器,需做降级处理;自定义控制能力弱(如无法自定义加载时机、加载动画)。
二、Intersection Observer API 实现(兼容性好,自定义能力强)

Intersection Observer 是浏览器提供的 API,可监听元素与视口(或指定容器)的“交叉状态”(即元素是否进入视口),无需手动计算滚动位置,性能优于传统 scroll 事件监听。

实现步骤:
  1. HTML 结构:用 data-src 存储真实图片地址,src 设为占位图;
  2. JS 逻辑:创建 Intersection Observer 实例,监听所有懒加载图片,当图片进入视口时,替换 srcdata-src 并停止监听。
<!-- HTML:占位图 + data-src 存真实地址 -->
<img class="lazy-img" src="placeholder.png" data-src="image1.jpg" alt="图1" width="600" height="400">
<img class="lazy-img" src="placeholder.png" data-src="image2.jpg" alt="图2" width="600" height="400">

<script>
// JS:Intersection Observer 监听
document.addEventListener('DOMContentLoaded', () => {
     
     
  // 1. 选择所有懒加载图片
  const lazyImages = document.querySelectorAll('.lazy-img');

  // 2. 创建观察者实例:交叉时执行回调
  const observer = new IntersectionObserver((entries, observer) => {
     
     
    entries.forEach(entry => {
     
     
      // 3. 若图片进入视口(isIntersecting 为 true)
      if (entry.isIntersecting) {
     
     
        const img = entry.target;
        // 替换 src 为真实地址(加载图片)
        img.src = img.dataset.src;
        // 可选:加载完成后添加动画
        img.onload = () => {
     
     
          img.classList.add('fade-in');
        };
        // 4. 停止监听已加载的图片(避免重复触发)
        observer.unobserve(img);
      }
    });
  }, {
     
     
    // 可选配置:距离视口 200px 时开始加载(提前预加载)
    rootMargin: '200px 0px',
    // 可选:交叉比例达到 10% 时触发(默认 0,即只要有一点进入就触发)
    threshold: 0.1
  });

  // 5. 给所有懒加载图片添加监听
  lazyImages.forEach(img => {
     
     
    observer.observe(img);
  });
});
</script>

<style>
/* 可选:加载动画 */
.lazy-img {
     
     
  transition: opacity 0.3s ease
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值