怎么优化首屏加载?

怎么优化首屏加载?

  • 1.什么是首屏加载
  • 2.首屏加载慢的原因
  • 3.优化首屏加载
    • 3.1 压缩和合并资源
    • 3.2 图片优化
    • 3.3 预加载或者懒加载策略
      • 3.3.1 懒加载策略
      • 3.3.2 预加载策略
    • 3.4 静态资源本地缓存
    • 3.5 减少代码体积
    • 3.6 CDN加速
    • 3.7 服务端渲染(SSR)
    • 3.8 感知性能优化
  • 4.总结

1.什么是首屏加载

首屏时间(First Contentful Paint),指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容

2.首屏加载慢的原因

在页面渲染的过程,导致加载速度慢的因素可能如下:

  • 网络延时问题
  • 资源文件体积是否过大
  • 资源是否重复发送请求去加载了
  • 加载脚本的时候,渲染内容堵塞了

3.优化首屏加载

3.1 压缩和合并资源

通过压缩CSS、JavaScript和HTML等静态资源文件,并将它们合并为较少的文件,可以减少网络请求次数和文件大小,加快页面加载速度。

压缩:
以下是一个示例Webpack配置文件,展示如何使用css-minimizer-webpack-pluginmini-css-extract-plugin压缩CSS文件和terser-webpack-plugin压缩JavaScript文件。

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
 
module.exports = {
  // 入口文件
  entry: './src/index.js',
  // 输出文件
  output: {
    filename: 'bundle.min.js',
    path: __dirname + '/dist',
  },
  // 模块加载器
  module: {
    rules: [
      // 处理CSS文件
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
      // 处理JavaScript文件
      {
        test: /\.js$/i,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react'],
          },
        },
      },
    ],
  },
  // 插件
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'styles.min.css',
    }),
  ],
  // 优化配置
  optimization: {
    minimizer: [
      // 压缩CSS文件
      new CssMinimizerPlugin(),
      // 压缩JavaScript文件
      new TerserPlugin(),
    ],
  },
};

合并静态资源:
在index.html文件中,我们将引入压缩和合并后的静态资源文件。

<html>
<head>
  <meta charset="UTF-8">
  <title>React App</title>
  <link rel="stylesheet" href="styles.min.css">
</head>
<body>
  <div id="root"></div>
 
  <script src="bundle.min.js"></script>
</body>
</html>

通过上述代码,我们将压缩和合并后的CSS文件和JavaScript文件引入到了index.html中。这样做可以减少网络请求次数和文件大小,提高页面加载速度。

3.2 图片优化

使用适当的图片格式(如JPEG、PNG、WebP)和压缩算法,对图片进行优化,减小图片文件大小,提高加载速度。

3.3 预加载或者懒加载策略

3.3.1 懒加载策略

下面是懒加载示例代码:

<!DOCTYPE html>
<html>
<head>
  <style>
    .image-container {
      height: 200px;
      width: 200px;
      overflow: hidden;
      background-color: #eee;
    }
 
    img {
      display: block;
      height: auto;
      width: 100%;
    }
  </style>
</head>
<body>
  <div class="image-container">
    <img data-src="image.jpg" alt="Image" />
  </div>
</body>
<script>
  document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll("img[data-src]"));
  if ("IntersectionObserver" in window) {
    var lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          var lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.removeAttribute("data-src");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });
 
    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } else {
    // Fallback for browsers that don't support IntersectionObserver
    var lazyLoad = function() {
      lazyImages.forEach(function(lazyImage) {
        if (lazyImage.getBoundingClientRect().top <= window.innerHeight && lazyImage.getBoundingClientRect().bottom >= 0 && getComputedStyle(lazyImage).display !== "none") {
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.removeAttribute("data-src");
          lazyImages = lazyImages.filter(function(image) {
            return image !== lazyImage;
          });
 
          if (lazyImages.length === 0) {
            document.removeEventListener("scroll", lazyLoad);
            window.removeEventListener("resize", lazyLoad);
            window.removeEventListener("orientationchange", lazyLoad);
          }
        }
      });
    };
 
    document.addEventListener("scroll", lazyLoad);
    window.addEventListener("resize", lazyLoad);
    window.addEventListener("orientationchange", lazyLoad);
  }
});
 
</script>
</html>

示例代码使用 IntersectionObserver API 实现图片懒加载,如果浏览器不支持该 API,则会回退到基于滚动事件的实现方式。

具体来说,该示例首先获取所有带有 data-src 属性的图片元素,并将它们保存在一个数组中。然后,如果浏览器支持 IntersectionObserver API,则创建一个 IntersectionObserver 对象,并为每个图片元素添加观察器。当图片元素进入视口时,观察器会将其 data-src 属性值设置为 src 属性值,并移除 data-src 属性。最后,观察器会取消对该图片元素的观察。

如果浏览器不支持 IntersectionObserver API,则会使用一个 lazyLoad 函数,该函数会在滚动、窗口大小调整或设备方向变化时被触发。在该函数中,会遍历所有带有 data-src 属性的图片元素,并检查它们是否在视口中可见。如果是,则将其 data-src 属性值设置为 src 属性值,并移除 data-src 属性。最后,会从数组中删除已经加载的图片元素,并检查数组是否为空。如果为空,则取消事件监听。

3.3.2 预加载策略

‌JavaScript预加载(Preloading)‌是一种前端性能优化技术,其核心思想是在用户实际需要某些资源之前,提前将这些资源加载到浏览器缓存中。这样,当用户访问这些资源时,可以直接从本地缓存中获取,从而减少等待时间,提升用户体验。

主要利用的是浏览器缓存。如下面是使用promise的预加载策略:

<script>
      //这个代码放在页面加载之前执行
      const loadImgAsync = function (path) {
        return new Promise((resolve, reject) => {
          let img = new Image();
          img.onload = function () {
            resolve(img);
          };
          img.onerror = function () {
            reject(new Error(`Could not load image at ${path}`));
          };
          img.src = path;
        });
      };
      const img = document.querySelector("#img");
      loadImgAsync(
        "https://scpic.chinaz.net/files/pic/pic9/202009/apic27858.jpg"
      )
        .then((res) => {
          img.src = res.src;
        })
        .catch((err) => {
          console.log(err);
        });
</script>

3.4 静态资源本地缓存

  • 采用HTTP缓存,设置Cache-Control,Last-Modified,Etag等响应头控制浏览器缓存
  • 采用Service Worker离线缓存
  • 前端合理利用localStorage

3.5 减少代码体积

  • 使用Tree Shaking防止冗余代码被打包;
  • 通过配置exclude&include属性、优化loader正则匹配来指定文件构建,避免不必要的文件被打包;
  • 对代码进行Code Splitting,遵循小即是块的原则;
  • 合理选择source-map优化代码调试;
  • 使用externals配置来提取常用库;

3.6 CDN加速

使用内容分发网络(CDN)来加速静态资源的传输,将资源缓存在离用户较近的服务器上,减少网络延迟。

下面以一个网站为例,说明CDN如何工作:

假设有一个名为www.example.com的网站,该网站拥有许多静态资源,如图像、CSS文件和JavaScript文件等。这些资源可能存储在网站的主机上,但是由于主机的位置和用户之间的距离不同,因此用户在访问这些资源时可能会遇到网络延迟。

为了解决这个问题,网站所有者可以使用CDN服务。CDN服务通常由多个服务器组成,这些服务器分布在全球各地,每个服务器都缓存了网站的静态资源。当用户请求这些资源时,CDN会将请求路由到最近的服务器,从而减少网络延迟并提高资源加载速度。

例如,当用户从中国访问www.example.com时,CDN会将用户请求路由到位于中国的服务器。如果该服务器上已经缓存了所需的静态资源,那么用户将立即获得资源。否则,CDN将从主机上获取资源,并将其缓存到服务器上,以便以后的请求可以更快地获取资源。

总之,使用CDN可以提高网站性能,减少网络延迟,提高用户体验。

一般直接在模板中使用script标签src属性引用。 也可以在项目中配置基础路径。

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
 
module.exports = {
  // 其他配置项...
  
  output: {
    // 设置输出路径和文件名
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
    publicPath: 'https://cdn.example.com/' // 设置CDN路径
  },
  
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      // 在HTML模板中使用CDN路径
      cdnPath: 'https://cdn.example.com/'
    }),
    // 其他插件...
  ],
  
  // 其他配置项...
};

3.7 服务端渲染(SSR)

缘由
SSR(服务器端渲染)能够提高首屏渲染的原因有以下几点:

  • 减少客户端渲染时间:在传统的客户端渲染中,浏览器需要下载HTML文件,然后执行JavaScript代码来生成并填充页面内容。而在SSR中,服务器会在响应请求时直接生成完整的HTML页面,并包含所需的数据。这样,浏览器只需要下载已经渲染好的HTML,减少了客户端渲染的时间。
  • 提前获取数据:在客户端渲染中,通常需要通过异步请求获取数据,然后再进行页面渲染。而在SSR中,服务器会在渲染过程中获取所需的数据,并将数据直接注入到HTML中。这样可以避免客户端请求数据的延迟,加快了首屏渲染的速度。
  • 更好的SEO:由于搜索引擎爬虫更容易解析和索引静态HTML页面,使用SSR可以提供更好的SEO效果。因为在SSR中,服务器返回的是已经渲染好的HTML页面,而不是由JavaScript生成的动态内容。这使得搜索引擎可以更好地理解和索引网页内容,提高了网站在搜索结果中的可见性。
  • 更好的用户体验:由于SSR能够更快地呈现出首屏内容,用户可以更快地看到页面的基本结构和内容,减少了等待时间,提升了用户体验。

可选用框架
前端可以使用一些框架或库来实现服务器端渲染(SSR),下面是几个常用的前端框架:

  • Next.js:Next.js是一个基于React的SSR框架。它提供了简单的API和约定,使得构建SSR应用变得更加容易。Next.js支持自动代码分割、预取和缓存,以提高性能。它还提供了静态导出功能,可以将应用程序预渲染为静态HTML文件。
  • Nuxt.js:Nuxt.js是一个基于Vue.js的SSR框架。它提供了类似于Next.js的功能,可以帮助开发者快速构建Vue.js应用的SSR版本。Nuxt.js支持自动路由、代码分割和服务端数据获取等特性。
  • Angular Universal:Angular Universal是Angular官方提供的SSR解决方案。它允许在服务器上预渲染Angular应用,以提供更好的性能和SEO效果。Angular Universal可以与Angular CLI集成,方便开发者进行构建和部署。

3.8 感知性能优化

loading或者骨架屏

4.总结

  • 压缩资源
    各种插件压缩、gzip压缩、使用适当的图片格式和压缩算法压缩图片
  • 合并代码减少http请求次数
    使用打包工具来辅助合并代码、图片雪碧图
  • 预加载或者懒加载策略
    图片懒加载、路由懒加载、异步组件、资源预加载
  • 静态资源本地缓存
  • 减少打包体积
    使用打包工具合理配置、UI框架按需加载…
  • CDN加速
  • SSR渲染
  • 感知性能优化
    loading、骨架屏

你可能感兴趣的:(面试,前端,前端,首屏优化)