写给中高级前端关于性能优化的9大策略和6大指标 | 网易四年实践

发表于 3年以前  | 总阅读数:231 次

前言

笔者近半年一直在参与项目重构,在重构过程中大量应用「性能优化」「设计模式」两方面的知识。「性能优化」「设计模式」两方面的知识不管在工作还是面试时都是高频应用场景,趁着这次参与大规模项目重构的机会,笔者认真梳理出一些常规且必用的性能优化建议,同时结合日常开发经验整理出笔者在网易四年来实践到的认为有用的所有性能优化建议,与大家一起分享分享!(由于篇幅有限,那设计模式在后面再专门出一篇文章呗)

可能有些性能优化建议已被大家熟知,不过也不影响这次分享,当然笔者也将一些平时可能不会注意的细节罗列出来。

平时大家认为性能优化是一种无序的应用场景,但在笔者看来它是一种有序的应用场景且很多性能优化都是互相铺垫甚至一带一路。从过程趋势来看,性能优化可分为「网络层面」「渲染层面」;从结果趋势来看,性能优化可分为「时间层面」「体积层面」。简单来说就是要在访问网站时使其快准狠地立马呈现在用户眼前

性能优化.png所有的性能优化都围绕着两大层面两小层面实现,核心层面是网络层面渲染层面,辅助层面是时间层面体积层面,而辅助层面则充满在核心层面里。于是笔者通过本文整理出关于前端性能优化「九大策略」「六大指标」。当然这些策略指标都是笔者自己定义,方便通过某种方式为性能优化做一些规范。

因此在工作或面试时结合这些特征就能完美地诠释性能优化所延伸出来的知识了。「前方高能,不看也得收藏,走起!!!」

所有代码示例为了凸显主题,只展示核心配置代码,其他配置并未补上,请自行脑补

九大策略

网络层面

「网络层面」的性能优化,无疑是如何让资源体积更小加载更快,因此笔者从以下四方面做出建议。

  • 「构建策略」:基于构建工具(Webpack/Rollup/Parcel/Esbuild/Vite/Gulp)
  • 「图像策略」:基于图像类型(JPG/PNG/SVG/WebP/Base64)
  • 「分发策略」:基于内容分发网络(CDN)
  • 「缓存策略」:基于浏览器缓存(强缓存/协商缓存)

上述四方面都是一步接着一步完成,充满在整个项目流程里。「构建策略」「图像策略」处于开发阶段,「分发策略」「缓存策略」处于生产阶段,因此在每个阶段都可检查是否按顺序接入上述策略。通过这种方式就能最大限度增加性能优化应用场景。

构建策略

该策略主要围绕webpack做相关处理,同时也是接入最普遍的性能优化策略。其他构建工具的处理也是大同小异,可能只是配置上不一致。说到webpack性能优化,无疑是从时间层面体积层面入手。

笔者发现目前webpack v5整体兼容性还不是特别好,某些功能配合第三方工具可能出现问题,故暂未升级到v5,继续使用v4作为生产工具,故以下配置均基于v4,但总体与v5的配置出入不大

笔者对两层面分别做出6个性能优化建议总共12个性能优化建议,为了方便记忆均使用四字词语概括,方便大家消化。⏱表示减少打包时间,表示减少打包体积

  • 「减少打包时间」缩减范围缓存副本定向搜索提前构建并行构建可视结构
  • 「减少打包体积」分割代码摇树优化动态垫片按需加载作用提升压缩资源

⏱缩减范围

「配置include/exclude缩小Loader对文件的搜索范围」,好处是避免不必要的转译node_modules目录的体积这么大,那得增加多少时间成本去检索所有文件啊?

include/exclude通常在各大Loader里配置,src目录通常作为源码目录,可做如下处理。当然include/exclude可根据实际情况修改。

export default {
    // ...
    module: {
        rules: [{
            exclude: /node_modules/,
            include: /src/,
            test: /\.js$/,
            use: "babel-loader"
        }]
    }
};

⏱缓存副本

「配置cache缓存Loader对文件的编译副本」,好处是再次编译时只编译修改过的文件。未修改过的文件干嘛要随着修改过的文件重新编译呢?

大部分Loader/Plugin都会提供一个可使用编译缓存的选项,通常包含cache字眼。以babel-loadereslint-webpack-plugin为例。

import EslintPlugin from "eslint-webpack-plugin";

export default {
    // ...
    module: {
        rules: [{
            // ...
            test: /\.js$/,
            use: [{
                loader: "babel-loader",
                options: { cacheDirectory: true }
            }]
        }]
    },
    plugins: [
        new EslintPlugin({ cache: true })
    ]
};

⏱定向搜索

「配置resolve提高文件的搜索速度」,好处是定向指定必须文件路径。若某些第三方库以常规形式引入可能报错或希望程序自动索引特定类型文件都可通过该方式解决。

alias映射模块路径,extensions表明文件后缀,noParse过滤无依赖文件。通常配置aliasextensions就足够。

export default {
    // ...
    resolve: {
        alias: {
            "#": AbsPath(""), // 根目录快捷方式
            "@": AbsPath("src"), // src目录快捷方式
            swiper: "swiper/js/swiper.min.js"
        }, // 模块导入快捷方式
        extensions: [".js", ".ts", ".jsx", ".tsx", ".json", ".vue"] // import路径时文件可省略后缀名
    }
};

⏱提前构建

「配置DllPlugin将第三方依赖提前打包」,好处是将DLL与业务代码完全分离且每次只构建业务代码。这是一个古老配置,在webpack v2时已存在,不过现在webpack v4+已不推荐使用该配置,因为其版本迭代带来的性能提升足以忽略DllPlugin所带来的效益。

「DLL」意为动态链接库,指一个包含可由多个程序同时使用的代码库。在前端领域里可认为是另类缓存的存在,它把公共代码打包为DLL文件并存到硬盘里,再次打包时动态链接DLL文件就无需再次打包那些公共代码,从而提升构建速度,减少打包时间。

配置DLL总体来说相比其他配置复杂,配置流程可大致分为三步。

首先告知构建脚本哪些依赖做成DLL并生成DLL文件DLL映射表文件

import { DefinePlugin, DllPlugin } from "webpack";

export default {
    // ...
    entry: {
        vendor: ["react", "react-dom", "react-router-dom"]
    },
    mode: "production",
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {
                    chunks: "all",
                    name: "vendor",
                    test: /node_modules/
                }
            }
        }
    },
    output: {
        filename: "[name].dll.js", // 输出路径和文件名称
        library: "[name]", // 全局变量名称:其他模块会从此变量上获取里面模块
        path: AbsPath("dist/static") // 输出目录路径
    },
    plugins: [
        new DefinePlugin({
            "process.env.NODE_ENV": JSON.stringify("development") // DLL模式下覆盖生产环境成开发环境(启动第三方依赖调试模式)
        }),
        new DllPlugin({
            name: "[name]", // 全局变量名称:减小搜索范围,与output.library结合使用
            path: AbsPath("dist/static/[name]-manifest.json") // 输出目录路径
        })
    ]
};

然后在package.json里配置执行脚本且每次构建前首先执行该脚本打包出DLL文件

{
    "scripts": {
        "dll": "webpack --config webpack.dll.js"
    }
}

最后链接DLL文件并告知webpack可命中的DLL文件让其自行读取。使用html-webpack-tags-plugin在打包时自动插入DLL文件

import { DllReferencePlugin } from "webpack";
import HtmlTagsPlugin from "html-webpack-tags-plugin";

export default {
    // ...
    plugins: [
        // ...
        new DllReferencePlugin({
            manifest: AbsPath("dist/static/vendor-manifest.json") // manifest文件路径
        }),
        new HtmlTagsPlugin({
            append: false, // 在生成资源后插入
            publicPath: "/", // 使用公共路径
            tags: ["static/vendor.dll.js"] // 资源路径
        })
    ]
};

为了那几秒钟的时间成本,笔者建议配置上较好。当然也可使用autodll-webpack-plugin代替手动配置。

⏱并行构建

「配置Thread将Loader单进程转换为多进程」,好处是释放CPU多核并发的优势。在使用webpack构建项目时会有大量文件需解析和处理,构建过程是计算密集型的操作,随着文件增多会使构建过程变得越慢。

运行在Node里的webpack是单线程模型,简单来说就是webpack待处理的任务需一件件处理,不能同一时刻处理多件任务。

文件读写计算操作无法避免,能不能让webpack同一时刻处理多个任务,发挥多核CPU电脑的威力以提升构建速度呢?thread-loader来帮你,根据CPU个数开启线程。

在此需注意一个问题,若项目文件不算多就不要使用该性能优化建议,毕竟开启多个线程也会存在性能开销。

import Os from "os";

export default {
    // ...
    module: {
        rules: [{
            // ...
            test: /\.js$/,
            use: [{
                loader: "thread-loader",
                options: { workers: Os.cpus().length }
            }, {
                loader: "babel-loader",
                options: { cacheDirectory: true }
            }]
        }]
    }
};

⏱可视结构

「配置BundleAnalyzer分析打包文件结构」,好处是找出导致体积过大的原因。从而通过分析原因得出优化方案减少构建时间。BundleAnalyzerwebpack官方插件,可直观分析打包文件的模块组成部分、模块体积占比、模块包含关系、模块依赖关系、文件是否重复、压缩体积对比等可视化数据。

可使用webpack-bundle-analyzer配置,有了它,我们就能快速找到相关问题。

import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";

export default {
    // ...
    plugins: [
        // ...
        BundleAnalyzerPlugin()
    ]
};

分割代码

「分割各个模块代码,提取相同部分代码」,好处是减少重复代码的出现频率webpack v4使用splitChunks替代CommonsChunksPlugin实现代码分割。

splitChunks配置较多,详情可参考官网,在此笔者贴上常用配置。

export default {
    // ...
    optimization: {
        runtimeChunk: { name: "manifest" }, // 抽离WebpackRuntime函数
        splitChunks: {
            cacheGroups: {
                common: {
                    minChunks: 2,
                    name: "common",
                    priority: 5,
                    reuseExistingChunk: true, // 重用已存在代码块
                    test: AbsPath("src")
                },
                vendor: {
                    chunks: "initial", // 代码分割类型
                    name: "vendor", // 代码块名称
                    priority: 10, // 优先级
                    test: /node_modules/ // 校验文件正则表达式
                }
            }, // 缓存组
            chunks: "all" // 代码分割类型:all全部模块,async异步模块,initial入口模块
        } // 代码块分割
    }
};

摇树优化

「删除项目中未被引用代码」,好处是移除重复代码和未使用代码摇树优化首次出现于rollup,是rollup的核心概念,后来在webpack v2里借鉴过来使用。

摇树优化只对ESM规范生效,对其他模块规范失效。摇树优化针对静态结构分析,只有import/export才能提供静态的导入/导出功能。因此在编写业务代码时必须使用ESM规范才能让摇树优化移除重复代码和未使用代码。

webpack里只需将打包环境设置成生产环境就能让摇树优化生效,同时业务代码使用ESM规范编写,使用import导入模块,使用export导出模块。

export default {
    // ...
    mode: "production"
};

动态垫片

「通过垫片服务根据UA返回当前浏览器代码垫片」,好处是无需将繁重的代码垫片打包进去。每次构建都配置@babel/preset-envcore-js根据某些需求将Polyfill打包进来,这无疑又为代码体积增加了贡献。

@babel/preset-env提供的useBuiltIns可按需导入Polyfill

  • 「false」:无视target.browsers将所有Polyfill加载进来
  • 「entry」:根据target.browsers将部分Polyfill加载进来(仅引入有浏览器不支持的Polyfill,需在入口文件import "core-js/stable")
  • 「usage」:根据target.browsers和检测代码里ES6的使用情况将部分Polyfill加载进来(无需在入口文件import "core-js/stable")

在此推荐大家使用动态垫片动态垫片可根据浏览器UserAgent返回当前浏览器Polyfill,其思路是根据浏览器的UserAgentbrowserlist查找出当前浏览器哪些特性缺乏支持从而返回这些特性的Polyfill。对这方面感兴趣的同学可参考polyfill-library和polyfill-service的源码。

在此提供两个动态垫片服务,可在不同浏览器里点击以下链接看看输出不同的Polyfill。相信IExplore还是最多Polyfill的,它自豪地说:我就是我,不一样的烟火

  • 「官方CDN服务」:https://polyfill.io/v3/polyfill.min.js
  • 「阿里CDN服务」:https://polyfill.alicdn.com/polyfill.min.js

使用html-webpack-tags-plugin在打包时自动插入动态垫片

import HtmlTagsPlugin from "html-webpack-tags-plugin";

export default {
    plugins: [
        new HtmlTagsPlugin({
            append: false, // 在生成资源后插入
            publicPath: false, // 使用公共路径
            tags: ["https://polyfill.alicdn.com/polyfill.min.js"] // 资源路径
        })
    ]
};

按需加载

「将路由页面/触发性功能单独打包为一个文件,使用时才加载」,好处是减轻首屏渲染的负担。因为项目功能越多其打包体积越大,导致首屏渲染速度越慢。

首屏渲染时只需对应JS代码而无需其他JS代码,所以可使用按需加载webpack v4提供模块按需切割加载功能,配合import()可做到首屏渲染减包的效果,从而加快首屏渲染速度。只有当触发某些功能时才会加载当前功能的JS代码

webpack v4提供魔术注解命名切割模块,若无注解则切割出来的模块无法分辨出属于哪个业务模块,所以一般都是一个业务模块共用一个切割模块的注解名称。

const Login = () => import( /* webpackChunkName: "login" */ "../../views/login");
const Logon = () => import( /* webpackChunkName: "logon" */ "../../views/logon");

运行起来控制台可能会报错,在package.jsonbabel相关配置里接入@babel/plugin-syntax-dynamic-import即可。

{
    // ...
    "babel": {
        // ...
        "plugins": [
            // ...
            "@babel/plugin-syntax-dynamic-import"
        ]
    }
}

作用提升

「分析模块间依赖关系,把打包好的模块合并到一个函数中」,好处是减少函数声明和内存花销作用提升首次出现于rollup,是rollup的核心概念,后来在webpack v3里借鉴过来使用。

在未开启作用提升前,构建后的代码会存在大量函数闭包。由于模块依赖,通过webpack打包后会转换成IIFE,大量函数闭包包裹代码会导致打包体积增大(模块越多越明显)。在运行代码时创建的函数作用域变多,从而导致更大的内存开销。

在开启作用提升后,构建后的代码会按照引入顺序放到一个函数作用域里,通过适当重命名某些变量以防止变量名冲突,从而减少函数声明和内存花销。

webpack里只需将打包环境设置成生产环境就能让作用提升生效,或显式设置concatenateModules

export default {
    // ...
    mode: "production"
};
// 显式设置
export default {
    // ...
    optimization: {
        // ...
        concatenateModules: true
    }
};

压缩资源

「压缩HTML/CSS/JS代码,压缩字体/图像/音频/视频」,好处是更有效减少打包体积。极致地优化代码都有可能不及优化一个资源文件的体积更有效。

针对HTML代码,使用html-webpack-plugin开启压缩功能。

import HtmlPlugin from "html-webpack-plugin";

export default {
    // ...
    plugins: [
        // ...
        HtmlPlugin({
            // ...
            minify: {
                collapseWhitespace: true,
                removeComments: true
            } // 压缩HTML
        })
    ]
};

针对CSS/JS代码,分别使用以下插件开启压缩功能。其中OptimizeCss基于cssnano封装,UglifyjsTerser都是webpack官方插件,同时需注意压缩JS代码需区分ES5ES6

  • optimize-css-assets-webpack-plugin:压缩CSS代码
  • uglifyjs-webpack-plugin:压缩ES5版本的JS代码
  • terser-webpack-plugin:压缩ES6版本的JS代码
import OptimizeCssAssetsPlugin from "optimize-css-assets-webpack-plugin";
import TerserPlugin from "terser-webpack-plugin";
import UglifyjsPlugin from "uglifyjs-webpack-plugin";

const compressOpts = type => ({
    cache: true, // 缓存文件
    parallel: true, // 并行处理
    [`${type}Options`]: {
        beautify: false,
        compress: { drop_console: true }
    } // 压缩配置
});
const compressCss = new OptimizeCssAssetsPlugin({
    cssProcessorOptions: {
        autoprefixer: { remove: false }, // 设置autoprefixer保留过时样式
        safe: true // 避免cssnano重新计算z-index
    }
});
const compressJs = USE_ES6
    ? new TerserPlugin(compressOpts("terser"))
    : new UglifyjsPlugin(compressOpts("uglify"));

export default {
    // ...
    optimization: {
        // ...
        minimizer: [compressCss, compressJs] // 代码压缩
    }
};

针对字体/音频/视频文件,还真没相关Plugin供我们使用,就只能拜托大家在发布项目到生产服前使用对应的压缩工具处理了。针对图像文件,大部分Loader/Plugin封装时均使用了某些图像处理工具,而这些工具的某些功能又托管在国外服务器里,所以导致经常安装失败。具体解决方式可回看笔者曾经发布的《聊聊NPM镜像那些险象环生的坑》一文寻求答案。

鉴于此,笔者花了一点小技巧开发了一个Plugin用于配合webpack压缩图像,详情请参考tinyimg-webpack-plugin。

import TinyimgPlugin from "tinyimg-webpack-plugin";

export default {
    // ...
    plugins: [
        // ...
        TinyimgPlugin()
    ]
};

上述构建策略都集成到笔者开源的bruce-cli里,它是一个「React/Vue」应用自动化构建脚手架,其零配置开箱即用的优点非常适合入门级、初中级、快速开发项目的前端同学使用,还可通过创建brucerc.js文件覆盖其默认配置,只需专注业务代码的编写无需关注构建代码的编写,让项目结构更简洁。详情请戳这里,使用时记得查看文档,支持一个Star哈!

图像策略

该策略主要围绕图像类型做相关处理,同时也是接入成本较低的性能优化策略。只需做到以下两点即可。

  • 「图像选型」:了解所有图像类型的特点及其何种应用场景最合适
  • 「图像压缩」:在部署到生产环境前使用工具或脚本对其压缩处理

图像选型一定要知道每种图像类型的体积/质量/兼容/请求/压缩/透明/场景等参数相对值,这样才能迅速做出判断在何种场景使用何种类型的图像。

类型 体积 质量 兼容 请求 压缩 透明 场景
JPG 有损 不支持 背景图、轮播图、色彩丰富图
PNG 是是 无损 支持 图标、透明图
SVG 是是是 无损 支持 图标、矢量图
WebP 兼备 支持 看兼容情况
Base64 看情况 否是 无损 支持 图标

图像压缩可在上述构建策略-压缩资源里完成,也可自行使用工具完成。由于现在大部分webpack图像压缩工具不是安装失败就是各种环境问题(你懂的),所以笔者还是推荐在发布项目到生产服前使用图像压缩工具处理,这样运行稳定也不会增加打包时间。

好用的图像压缩工具无非就是以下几个,若有更好用的工具麻烦在评论里补充喔!

工具 开源 收费 API 免费体验
QuickPicture ✖️ ✔️ ✖️ 可压缩类型较多,压缩质感较好,有体积限制,有数量限制
ShrinkMe ✖️ ✖️ ✖️ 可压缩类型较多,压缩质感一般,无数量限制,有体积限制
Squoosh ✔️ ✖️ ✔️ 可压缩类型较少,压缩质感一般,无数量限制,有体积限制
TinyJpg ✖️ ✔️ ✔️ 可压缩类型较少,压缩质感很好,有数量限制,有体积限制
TinyPng ✖️ ✔️ ✔️ 可压缩类型较少,压缩质感很好,有数量限制,有体积限制
Zhitu ✖️ ✖️ ✖️ 可压缩类型一般,压缩质感一般,有数量限制,有体积限制

若不想在网站里来回拖动图像文件,可使用笔者开源的图像批处理工具img-master代替,不仅有压缩功能,还有分组功能、标记功能和变换功能。目前笔者负责的全部项目都使用该工具处理,一直用一直爽!

图像策略也许处理一张图像就能完爆所有构建策略,因此是一种很廉价但极有效的性能优化策略

分发策略

该策略主要围绕内容分发网络做相关处理,同时也是接入成本较高的性能优化策略,需足够资金支持。

虽然接入成本较高,但大部分企业都会购买一些CDN服务器,所以在部署的事情上就不用过分担忧,尽管使用就好。该策略尽量遵循以下两点就能发挥CDN最大作用。

  • 「所有静态资源走CDN」:开发阶段确定哪些文件属于静态资源
  • 「把静态资源与主页面置于不同域名下」:避免请求带上Cookie

「内容分发网络」简称「CDN」,指一组分布在各地存储数据副本并可根据就近原则满足数据请求的服务器。其核心特征是缓存回源,缓存是把资源复制到CDN服务器里,回源是资源过期/不存在就向上层服务器请求并复制到CDN服务器里。

使用CDN可降低网络拥塞,提高用户访问响应速度和命中率。构建在现有网络基础上的智能虚拟网络,依靠部署在各地服务器,通过中心平台的调度、负载均衡、内容分发等功能模块,使用户就近获取所需资源,这就是CDN的终极使命。

基于CDN「就近原则」所带来的优点,可将网站所有静态资源全部部署到CDN服务器里。那静态资源包括哪些文件?通常来说就是无需服务器产生计算就能得到的资源,例如不常变化的样式文件脚本文件多媒体文件(字体/图像/音频/视频)等。

若需单独配置CDN服务器,可考虑阿里云OSS、网易树帆NOS和七牛云Kodo,当然配置起来还需购买该产品对应的CDN服务。由于篇幅问题,这些配置在购买后会有相关教程,可自行体会,在此就不再叙述了。

笔者推荐大家首选网易树帆NOS,毕竟对自家产品还是挺有信心的,不小心给自家产品打了个小广告了,哈哈!

缓存策略

该策略主要围绕浏览器缓存做相关处理,同时也使接入成本最低的性能优化策略。其显著减少网络传输所带来的损耗,提升网页访问速度,是一种很值得使用的性能优化策略

通过下图可知,为了让浏览器缓存发挥最大作用,该策略尽量遵循以下五点就能发挥浏览器缓存最大作用。

  • 「考虑拒绝一切缓存策略」Cache-Control:no-store
  • 「考虑资源是否每次向服务器请求」Cache-Control:no-cache
  • 「考虑资源是否被代理服务器缓存」Cache-Control:public/private
  • 「考虑资源过期时间」Expires:t/Cache-Control:max-age=t,s-maxage=t
  • 「考虑协商缓存」Last-Modified/Etag

缓存判断机制

同时浏览器缓存也是高频面试题之一,笔者觉得上述涉及到的名词在不同语序串联下也能完全理解才能真正弄懂浏览器缓存性能优化里起到的作用。

缓存策略通过设置HTTP报文实现,在形式上分为「强缓存/强制缓存」「协商缓存/对比缓存」。为了方便对比,笔者将某些细节使用图例展示,相信你有更好的理解。

强缓存.png

协商缓存.png

整个缓存策略机制很明了,先走强缓存,若命中失败才走协商缓存。若命中强缓存,直接使用强缓存;若未命中强缓存,发送请求到服务器检查是否命中协商缓存;若命中协商缓存,服务器返回304通知浏览器使用本地缓存,否则返回最新资源

有两种较常用的应用场景值得使用缓存策略一试,当然更多应用场景都可根据项目需求制定。

  • 「频繁变动资源」:设置Cache-Control:no-cache,使浏览器每次都发送请求到服务器,配合Last-Modified/ETag验证资源是否有效
  • 「不常变化资源」:设置Cache-Control:max-age=31536000,对文件名哈希处理,当代码修改后生成新的文件名,当HTML文件引入文件名发生改变才会下载最新文件

渲染层面

「渲染层面」的性能优化,无疑是如何让代码解析更好执行更快。因此笔者从以下五方面做出建议。

  • 「CSS策略」:基于CSS规则
  • 「DOM策略」:基于DOM操作
  • 「阻塞策略」:基于脚本加载
  • 「回流重绘策略」:基于回流重绘
  • 「异步更新策略」:基于异步更新

上述五方面都是编写代码时完成,充满在整个项目流程的开发阶段里。因此在开发阶段需时刻注意以下涉及到的每一点,养成良好的开发习惯,性能优化也自然而然被使用上了。

渲染层面性能优化更多表现在编码细节上,而并非实体代码。简单来说就是遵循某些编码规则,才能将渲染层面性能优化发挥到最大作用。

「回流重绘策略」渲染层面性能优化里占比较重,也是最常规的性能优化之一。上年笔者发布的掘金小册《玩转CSS的艺术之美》使用一整章讲解回流重绘,本章已开通试读,更多细节请戳这里。

CSS策略
  • 避免出现超过三层的嵌套规则
  • 避免为ID选择器添加多余选择器
  • 避免使用标签选择器代替类选择器
  • 避免使用通配选择器,只对目标节点声明规则
  • 避免重复匹配重复定义,关注可继承属性
DOM策略
  • 缓存DOM计算属性
  • 避免过多DOM操作
  • 使用DOMFragment缓存批量化DOM操作
阻塞策略
  • 脚本与DOM/其它脚本的依赖关系很强:对<script>设置defer
  • 脚本与DOM/其它脚本的依赖关系不强:对<script>设置async
回流重绘策略
  • 缓存DOM计算属性
  • 使用类合并样式,避免逐条改变样式
  • 使用display控制DOM显隐,将DOM离线化
异步更新策略
  • 异步任务中修改DOM时把其包装成微任务

六大指标

笔者根据性能优化的重要性和实际性划分出九大策略六大指标,其实它们都是一条条活生生的性能优化建议。有些性能优化建议接不接入影响都不大,因此笔者将九大策略定位高于六大指标。针对九大策略还是建议在开发阶段和生产阶段接入,在项目复盘时可将六大指标的条条框框根据实际应用场景接入。

六大指标基本囊括大部分性能优化细节,可作为九大策略的补充。笔者根据每条性能优化建议的特征将指标划分为以下六方面。

  • 「加载优化」:资源在加载时可做的性能优化
  • 「执行优化」:资源在执行时可做的性能优化
  • 「渲染优化」:资源在渲染时可做的性能优化
  • 「样式优化」:样式在编码时可做的性能优化
  • 「脚本优化」:脚本在编码时可做的性能优化
  • 「V8引擎优化」:针对V8引擎特征可做的性能优化
加载优化

六大指标-加载优化.png

执行优化

六大指标-执行优化.png

渲染优化

六大指标-渲染优化.png

样式优化

六大指标-样式优化.png

脚本优化

六大指标-脚本优化.png

V8引擎优化

六大指标-V8引擎优化.png

总结

「性能优化」作为老生常谈的知识,必然会在工作或面试时遇上。很多时候不是想到某条性能优化建议就去做或答,而是要对这方面有一个整体认知,知道为何这样设计,这样设计的目的能达到什么效果。

性能优化不是通过一篇文章就能全部讲完,若详细去讲可能要写两本书的篇幅才能讲完。本文能到给大家的就是一个方向一种态度,学以致用呗,希望阅读完本文会对你有所帮助。

本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/mFkL_kwYlxDYJzrpvJlhJA

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237231次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8065次阅读
 目录