Frontend Development 20 min read

First Screen Optimization Techniques for Web Performance

This article explains what first‑screen optimization is and presents ten practical methods—including resource compression, image optimization, asynchronous loading, preloading, CSS/JS optimization, caching strategies, server‑side rendering, CDN acceleration, and delayed loading—complete with detailed Webpack configurations and code examples to improve initial page render speed.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
First Screen Optimization Techniques for Web Performance

前言

面试官问你首屏优化没有?

什么是

首屏优化是指在网页加载过程中,尽快展示给用户可见的内容,以提高用户体验和页面加载速度。

常用方法

1、压缩和合并资源

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

压缩

以下是一个示例Webpack配置文件,展示如何使用 css-minimizer-webpack-plugin 、 mini-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 文件中,我们将引入压缩和合并后的静态资源文件。

<!DOCTYPE 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 中,减少网络请求次数和文件大小,提高页面加载速度。

2、图片优化

使用适当的图片格式(如JPEG、PNG、WebP)和压缩算法,对图片进行优化,减小文件大小,并使用懒加载技术延迟加载非首屏可见的图片。

举例一个懒加载示例:

<!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>
  <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 {
        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>
</body>
</html>

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

3、异步加载

将不影响首屏展示的资源(如统计代码、广告等)使用异步加载方式引入,避免阻塞首屏内容的加载。

可以使用 JavaScript 动态创建 <script> 标签并插入文档,实现异步加载。

示例:

function loadExternalScript(url) {
  return new Promise((resolve, reject) => {
    const script = document.createElement('script');
    script.src = url;
    script.async = true;
    script.onload = () => { resolve(); };
    script.onerror = () => { reject(new Error(`Failed to load script ${url}`)); };
    document.head.appendChild(script);
  });
}

// 异步加载统计代码
loadExternalScript('https://example.com/analytics.js')
  .then(() => { console.log('Analytics script loaded'); })
  .catch(error => { console.error(error); });

// 异步加载广告代码
loadExternalScript('https://example.com/advertisement.js')
  .then(() => { console.log('Advertisement script loaded'); })
  .catch(error => { console.error(error); });

4、预加载关键资源

通过预加载关键资源(如字体文件、重要的 CSS 和 JavaScript 文件),在首屏展示之前提前加载这些资源,加快后续页面加载速度。

示例:

<!DOCTYPE html>
<html>
<head>
  <title>预加载关键资源示例</title>
  <link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
  <link rel="preload" href="styles.css" as="style" crossorigin>
  <link rel="preload" href="script.js" as="script" crossorigin>
  <style>
    /* 首屏样式 */
    body {font-family: 'FontName', sans-serif;}
  </style>
  <link rel="stylesheet" href="styles.css">
  <script src="script.js" defer></script>
</head>
<body>
  <!-- 页面内容 -->
</body>
</html>

5、CSS优化

避免使用过多的 CSS 文件和行内样式,尽量减少 CSS 文件大小,并将 CSS 放在页面头部,以便尽早渲染页面。

<!DOCTYPE html>
<html>
  <head>
    <title>示例页面</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <h1>欢迎来到示例页面</h1>
    <p>这是一个简单的示例页面。</p>
  </body>
</html>

6、JavaScript优化

将 JavaScript 代码放在页面底部,减少对页面渲染的阻塞,并通过压缩、去除不必要的注释和空格来减小文件体积。

<!DOCTYPE html>
<html>
<head>
  <title>JavaScript代码放在页面底部示例</title>
</head>
<body>
  <!-- 页面内容 -->
  <script src="script.js"></script>
</body>
</html>

7、缓存策略

合理设置缓存策略,利用浏览器缓存减少重复加载相同资源的次数,提高页面加载速度。

// 假设我们有一个名为 "api.js" 的模块,用于发送网络请求

// 缓存对象,用于存储已经请求过的数据和过期时间
const cache = {};

// 发送网络请求的函数
async function fetchData(url) {
  // 检查缓存中是否存在数据
  if (cache[url] && cache[url].expires > Date.now()) {
    console.log('从缓存中获取数据:', cache[url].data);
    return cache[url].data;
  }

  // 发送网络请求
  const response = await fetch(url);
  const data = await response.json();

  // 设置缓存有效期为1小时
  const expires = Date.now() + 3600000;

  // 将数据和过期时间存入缓存
  cache[url] = { data, expires };

  console.log('从服务器获取数据:', data);
  return data;
}

async function getData() {
  const url = 'https://api.example.com/data';
  try {
    const data = await fetchData(url);
    console.log('处理数据:', data);
  } catch (error) {
    console.error('请求失败:', error);
  }
}

// 调用获取数据的函数
getData();

8、服务端渲染(SSR)

缘由

SSR 能够减少客户端渲染时间、提前获取数据、提升 SEO 并改善用户体验。

可选用框架

Next.js :基于 React 的 SSR 框架,支持自动代码分割、预取和缓存。

Nuxt.js :基于 Vue.js 的 SSR 框架,提供类似功能。

Angular Universal :Angular 官方的 SSR 解决方案。

9、CDN加速

使用内容分发网络(CDN)将静态资源缓存到离用户更近的服务器,减少网络延迟并提升加载速度。

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/'
    }),
    // 其他插件...
  ],
  // 其他配置项...
};

10、延迟加载非关键资源

将广告、推荐内容等非关键资源的加载延迟到首屏渲染完成之后,以提升首屏展示速度。

<!DOCTYPE html>
<html>
<head>
  <title>延迟加载示例</title>
</head>
<body>
  <h1>首屏内容</h1>
  <!-- 非关键资源 -->
  <div id="ad-container"></div>
  <script src="ad.js" defer></script>
  <script>
    // 首屏渲染完成后执行
    window.addEventListener('load', function() {
      // 加载广告
      var adContainer = document.getElementById('ad-container');
      var adScript = document.createElement('script');
      adScript.src = 'ad.js';
      adContainer.appendChild(adScript);
    });
  </script>
</body>
</html>

最后

你快回答他,说 "我知道!!是...这样!"

frontendPerformanceOptimizationWebpacklazy-loadingfirst-screen
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.