前端工程化、性能优化面试题44题
1.如何⽤ webpack 来优化前端性能?
要通过 Webpack 来优化前端性能,可以考虑以下一些优化策略:
-
代码分割(Code Splitting): 使用 Webpack 的代码分割功能,将代码拆分为多个小块,按需加载。这样可以减少初始加载时需要下载的资源量,提高页面的加载速度。
-
压缩代码: 使用 Webpack 的 UglifyJsPlugin 或 TerserPlugin 来压缩 JavaScript 代码,以减少文件大小,加快加载速度。注 uglifyjs-webpack-plugin、terser-webapck-plugin来压缩js代码,css-minimizer-webpack-plugin来压缩css代码
-
Tree Shaking: 通过 Webpack 的 Tree Shaking 功能,消除 JavaScript 中未使用的代码,减少最终打包文件的体积。
-
图片优化: 使用 image-webpack-loader 或者 url-loader 来优化图片资源,包括压缩图片、转换为 Base64 格式或者按需加载等方式。
-
使用 CDN: 将静态资源部署到 CDN 上,可以加速资源的加载速度,减轻服务器压力。
-
缓存优化: 通过 Webpack 的文件名哈希、chunkhash 等机制,实现文件名的缓存优化,确保文件更新后能够正确地被浏览器缓存。
-
懒加载和预加载: 使用 Webpack 实现懒加载和预加载,根据页面的实际需求来延迟加载某些资源或者提前加载可能需要的资源,以提高用户体验和性能。
-
使用Webpack实现懒加载和预加载可以通过动态导入(dynamic import)和webpack的代码分割(code splitting)功能来实现。以下是两种方式的简要说明:
- 懒加载(Lazy Loading):懒加载是指在页面实际需要时再去加载特定资源,而不是在初始加载时就加载所有资源。在Webpack中,可以使用动态导入(dynamic import)来实现懒加载。例如:
const button = document.getElementById('myButton');
button.addEventListener('click', async () => {
const module = await import('./module');
module.doSomething();
});在上面的例子中,当按钮被点击时,才会去动态加载'module'模块,实现了懒加载的效果。
- 预加载(Preloading):预加载是指在页面加载完成后,提前加载可能需要的资源,以提高用户体验和性能。在Webpack中,可以使用
prefetch或preload来实现预加载。例如:
import(/* webpackPrefetch: true */ './module');或者
import(/* webpackPreload: true */ './module');这样做可以告诉Webpack在空闲时提前加载指定模块,以便在未来可能需要时能够更快地加载。
通过使用动态导入和webpack的代码分割功能,可以灵活地实现懒加载和预加载,根据页面的实际需求来延迟加载某些资源或者提前加载可能需要的资源,从而提高用户体验和性能。
-
-
使用 Webpack 插件: 使用一些优化类的 Webpack 插件,如 MiniCssExtractPlugin 提取 CSS、HtmlWebpackPlugin 生成 HTML 文件、BundleAnalyzerPlugin 分析打包文件等,来帮助进行更细致的优化工作。
以上是一些基本的 Webpack 优化策略,实际项目中可以根据具体情况和需求,结合其他优化
2.如何提⾼ webpack 的打包速度?
要提高 Webpack 的打包速度,可以考虑以下一些优化策略:
- 使用最新版本的 Webpack: 每个新版本的 Webpack 都会带来性能方面的改进和优化,因此始终使用最新版本的 Webpack 可以获得更好的 性能表现。
- 合理配置 loader 和 plugin: 确保只加载必要的 loader 和 plugin,避免不必要的资源消耗。并且合理配置 loader 和 plugin 的选项,以免造成额外的性能开销。
- 使用 HappyPack: HappyPack 可以将 loader 的执行任务分配给多个子进程,从而加快构建速度。
- 使用 DllPlugin 和 DllReferencePlugin: 使用 DllPlugin 将第三方库(如 React、Vue 等)打包为单独的文件,然后使用 DllReferencePlugin 在开发环境和生产环境中引用该文件,减少打包时间。
- 使用缓存: 使用 Webpack 的缓存功能,减少重复构建的时间。可以使用 cache-loader 或者 hard-source-webpack-plugin 等插件来实现缓存。
- 优化文件搜索范围: 在配置 loader 和 plugin 时,尽量缩小文件搜索的范围,只对必要的文件进行处理,避免不必要的性能开销。
- 使用 Tree Shaking: 通过配置 Webpack,确保只打包使用到的代码,而不是将整个库都打包进去。
- 使用并行构建工具: 可以考虑使用类似于 parallel-webpack、thread-loader 等并行构建工具,以提高构建速度。
- 优化配置项: 对 Webpack 的配置文件进行优化,尽量简化配置,减少不必要的计算和处理。
通过以上优化策略,可以提高 Webpack 的打包速度。但需要注意的是,优化的效果可能因项目的具体情况而有所不同,因此建议在实施优化策略时,结合具体项目的需求和特点,进行合理的优化调整。
另外,还可以通过使用现代化的构建工具(如 Vite、esbuild 等)来替代 Webpack,在某些场景下可以获得更好的构建性能。在实际项目中,可以根据具体情况进行评估和选择。
3.如何提⾼ webpack 的构建速度?
要提高 Webpack 的构建速度,可以考虑以下一些优化策略:
- 使用最新版本的 Webpack: 每个新版本的 Webpack 都会带来性能方面的改进和优化,因此始终使用最新版本的 Webpack 可以获得更好的构建性能。
- 合理配置 loader 和 plugin: 确保只加载必要的 loader 和 plugin,避免不必要的资源消耗。并且合理配置 loader 和 plugin 的选项,以免造成额外的性能开销。
- 使用缓存: 使用 Webpack 的缓存功能,减少重复构建的时间。可以使用 cache-loader 或者 hard-source-webpack-plugin 等插件来实现缓存,避免每次构建都重新处理所有文件。
- 使用 Tree Shaking: 通过配置 Webpack,确保只打包使用到的代码,而不是将整个库都打包进去。这可以通过配置 optimization.treeShaking 来实现。
- 优化文件搜索范围: 在配置 loader 和 plugin 时,尽量缩小文件搜索的范围,只对必要的文件进行处理,避免不必要的性能开销。
- 使用并行构建工具: 可以考虑使用类似于 parallel-webpack、thread-loader 等并行构建工具,以提高构建速度。
- 优化配置项: 对 Webpack 的配置文件进行优化,尽量简化配置,减少不必要的计算和处理。
- 使用 DllPlugin 和 DllReferencePlugin: 使用 DllPlugin 将第三方库(如 React、Vue 等)打包为单独的文件,然后使用 DllReferencePlugin 在开发环境和生产环境中引用该文件,减少打包时间。
- 使用现代化构建工具: 在某些场景下,可以考虑使用现代化的构建工具(如 Vite、esbuild 等)来替代 Webpack,在某些场景下可以获得更好的构建性能。
- 使用持久缓存: Webpack 5 引入了持久性缓存,可以通过配置 cache.type: 'filesystem' 来启用,这样可以将构建结果缓存到磁盘中,提高重建速度。
- 优化输出文件: 对输出的文件进行优化,包括使用压缩算法、减少文件体积、合并文件等方式,以提高文件的传输和加载速度。
- 使用 CDN: 将静态资源部署到 CDN 上,可以加速资源的加载速度,减轻服务器压力。
以上是一些常见的 Webpack 构建速度优化策略,实际项目中可以根据具体情况和需求,结合其他优化手段来提高构建速度。
4.webpack 的构建流程
Webpack 的构建流程可以大致分为以下几个步骤:
-
解析配置文件: Webpack 会首先读取并解析项目中的配置文件(如 webpack.config.js),根据配置文件中的设置来确定需要构建的入口文件、输出文件路径、以及各种 loader、plugin 的配置等信息。
-
识别入口文件: 根据配置文件中指定的入口文件(entry),Webpack 开始递归解析入口文件及其依赖的模块。在这一过程中,Webpack 使用内置的模块解析器来分析模块之间的依赖关系。
-
执行 loader: 在识别并解析模块的过程中,Webpack 会根据配置文件中的规则,对不同类型的模块应用相应的 loader 进行转换。这可以包括将 ES6 代码转 换为 ES5、将 SCSS 转换为 CSS、对图片进行压缩等操作。
-
应用 plugin: 在模块转换完成后,Webpack 会执行配置中的各种 plugin,这些 plugin 可以用于完成各种任务,如代码压缩、资源提取、环境变量注入等。
-
生成输出文件: 经过 loader 和 plugin 的处理后,Webpack 将所有模块打包成一个或多个 bundle 文件。这些文件包括 JavaScript、CSS、图片等资源,它们可以通过浏览器访问并加载。
-
输出结果: 最后,Webpack 将打包生成的文件输出到指定的目录中,完成整个构建流程。
在以上步骤中,Webpack 会根据配置文件中的设置以及模块之间的依赖关系,对项目中的资源进行处理和打包,最终生成可以在浏览器中运行的静态文件。
5. babel 是什么,怎么做到的?
Babel 是一个广泛使用的 JavaScript 编译器,它的主要功能是将当前或旧版本的 JavaScript 代码转换为向后兼容的 JavaScript 代码,以便在当前和旧版本的浏览器或环境中运行。Babel 能够实现这一功能的原因在于它具备以下特点和功能:
-
语法转换:Babel 可以将 ECMAScript 2015+ 的新语法转换为向后兼容的 JavaScript 代码,这包括箭头函数、解构赋值、Promise 等新的语言特性。
-
API 转换:Babel 可以将 ECMAScript 2015+ 的新内置 API 转换为向后兼容的 JavaScript 代码,这包括 Set、Map、Symbol 等新的内置对象和方法。
-
Polyfill 添加:Babel 可以通过添加 polyfill 的方式来模拟新 API 的行为,使得旧版本的 JavaScript 运行环境也能够支持新的 API。
-
插件化:Babel 是一个高度可扩展的工具,它可以通过插件的方式来实现不同的转换功能,用户可以根据自己的需求选择不同的插件进行配置,以满足特定的转换需求。
Babel 实现这些功能的原理主要包括以下步骤:
-
词法分析和语法分析:Babel 首先会对输入的 JavaScript 代码进行词法分析和语法分析,将代码转换为抽象语法树(AST)的形式。
-
转换处理:Babel 会基于 AST 对代码进行转换处理,根据配置的插件和预设,对代码中的特定语法和 API 进行转换和兼容处理,例如将箭头函数转换为普通函数、
6. webpack 热更新的机制原理?
Webpack 的热更新(Hot Module Replacement,HMR)机制是一种能够在应用程序运行时替换、添加或删除模块而无需完全刷新页面的技术。它使开发人员能够在保持应用程序状态的同时,快速地查看对代码的更改。下面是Webpack热更新的基本原理:
-
启动 HMR 功能:在 webpack 配置中,通过启用
HotModuleReplacementPlugin插件来开启 HMR 功能。这个插件将会在应用运行时,替换、添加或删除模块而无需完全刷新页面。 -
监控文件变化:在开发模式下,Webpack Dev Server 会监控项目中所有文件的变化。当文件发生变化时,Webpack 会构建新的模块,并将这些 模块传递给 HMR runtime。
-
HMR Runtime:Webpack 在构建输出的 bundle 中包含了 HMR runtime,它负责在运行时接收来自 webpack Dev Server 的更新,并将这些更新应用到运行中的应用程序中。
-
模块热替换:当开发人员对代码进行修改后,Webpack Dev Server 会构建新的模块。然后 HMR runtime 会与 webpack Dev Server 通信,以确定哪些模块发生了变化。HMR runtime 将新模块的更新发送给应用程序,并使用更新后的模块替换旧模块,从而实现热更新。
总的来说,Webpack 热更新的机制原理是通过 HMR runtime 在运行时接收来自 webpack Dev Server 的更新,并将这些更新应用到运行中的应用程序中,从而实现模块的热替换,使得开发人员能够在保持应用程序状态的同时,快速地查看对代码的更改。
二、实现原理
首先来看看一张图,如下:

- Webpack Compile:将 JS 源代码编译成 bundle.js
- HMR Server:用来将热更新的文件输出给 HMR Runtime
- Bundle Server:静态资源文件服务器,提供文件访问路径
- HMR Runtime:socket 服务器,会被注入到浏览器,更新文件的变化
- bundle.js:构建输出的文件
- 在 HMR Runtime 和 HMR Server 之间建立 websocket,即图上 4 号线,用于实时更新文件变化
上面图中,可以分成两个阶段:
- 启动阶段为上图 1 - 2 - A - B
在编写未经过webpack打包的源代 码后,Webpack Compile将源代码和HMR Runtime一起编译成bundle文件,传输给Bundle Server静态资源服务器
- 更新阶段为上图 1 - 2 - 3 - 4
当某一个文件或者模块发生变化时,webpack监听到文件变化对文件重新编译打包,编译生成唯一的hash值,这个hash值用来作为下一次热更新的标识
根据变化的内容生成两个补丁文件:manifest(包含了hash和chundId,用来说明变化的内容)和chunk.js模块
由于socket服务器在HMR Runtime和HMR Server之间建立websocket链接,当文件发生改动的时候,服务端会向浏览器推送一条消息,消息包含文件改动后生成的hash值,如下图的h属性,作为下一次热更细的标识

在浏览器接受到这条消息之前,浏览器已经在上一次socket消息中已经记住了此时的hash标识,这时候我们会创建一个ajax去服务端请求获取到变化内容的manifest文件
mainfest文件包含重新build生成的hash值,以及变化的模块,对应上图的c属性
浏览器根据manifest文件获取模块变化的内容,从而触发render流程,实现局部模块更新

三、总结
关于webpack热模块更新的总结如下:
- 通过
webpack-dev-server创建两个服务器:提供静态资源的服务(express)和 Socket 服务 - express server 负责直接提供静态资源的服务(打包后的资源直接被浏览器请求和解析)
- socket server 是一个 websocket 的长连接,双方可以通信
- 当 socket server 监听到对应的模块发生变化时,会生成两个文件.json(manifest 文件)和.js 文件(update chunk)
- 通过长连接,socket server 可以直接将这两个文件主动发送给客户端(浏览器)
- 浏览器拿到两个新的文件后,通过 HMR runtime 机制,加载这两个文件,并且针对修改的模块进行更新
7. 是否有写过 webpack 插件?
了解 webpack 插件吗?
- 了解,webpack 的大致流程是,初始化配置 => 从入口模块开始解析 => 经过 loader 处理 => 遍历 ast => 找到依赖 => 继续解析依赖,直到所有的子模块都解析完成 => 优化 chunk => 生成 assets => 根据 assets 生成最终的产物
- 而这个过程中 webpack 不能满足所有的场景,为了 webpack 更加灵活与拓展,设计了插件机制,webpack 的插件机制,基于
tapable实现,而tapable提供了多种类型的 hook,比如同步串行 hook,异步并行 hook 等 - 然后 webpack 目前提供的 hook 大概有 5 类,第一类是 compiler 上的 hook,这类 hook 是大流程上的节点;第二类 complation 上的 hook,这类 hook 是构建模块实例、优化 chunk 等流程上的节点;第三类 NormalModuleFactory 上的 hook,这类 hook 是模块创建、超找模块等流程上节点;第四类是 JavascriptParser 上的 hook,这类 hook 就是遍历 ast 流程上的节点;第五类就是 ContextModuleFactory 上的 hook 与 NormalModuleFactory 上的 hook 类似,但是用的少
- 最后一个插件以 apply 方法作为入口函数,入口函数会接受一个 compiler 参数,接下来就是根据 webpack 在 compiler,compilation 等对象上爆料的 hooks 上注册 callback,在 callback 内完成拓展功能
写过 webpack 插件吗?
- 写过,我写过约定式路由插件(任何自己写的插件),写这个插件的目的是为了解决手写 routes 配置文件,做到自动生成 routes 文件,以高开发效率
- 为了使生成 routes 文件生效,我选择在 webpack 编译之前的 hooks 内完成 routes 文件的生成,而编译之前的 hooks 有,environment、initialize 等 hook,我这里选择 initialize hook,这一个同步串行 hook
- 最后在 initialize hook 上注册 callback,在 callback 内读取目录及相关的配置,生成路由配置文件
8. 谈下 webpack loader 机制?
Webpack Loader 机制是 Webpack 提供的一种机制,用于处理项目中的各种资源文件,例如 JavaScript 模块、样式表、图片、字体等。通过 Loader 机制,Webpack 可以将不同类型的文件转换为模块,并且可以在转换过程中应用各种转换操作, 例如编译、压缩、转译等。
Webpack Loader 机制的主要特点包括:
-
模块转换:Loader 可以将不同类型的文件转换为 JavaScript 模块,使得这些文件可以作为模块被引入和使用。
-
链式调用:多个 Loader 可以串联使用,每个 Loader 可以对模块进行转换,并将转换后的结果传递给下一个 Loader。
-
配置灵活:对于每个 Loader,可以通过配置选项进行定制化配置,从而满足各种不同的转换需求。
-
处理多种资源:除了 JavaScript 模块外,Loader 也可以处理样式表、图片、字体等各种资源文件,使得这些资源文件也可以成为模块被引入和使用。
在项目中使用 Loader 通常需要进行以下步骤:
-
安装 Loader 模块:首先需要通过 npm 或 yarn 安装所需的 Loader 模块,例如
babel-loader用于处理 JavaScript 文件、css-loader用于处理 CSS 文件等。 -
配置 Loader:在 webpack 的配置文件中,通过
module.rules配置项配置需要使用的 Loader,可以指定 Loader 的名称、处理的文件类型、Loader 的配置选项等。 -
链式调用:如果需要对文件进行多步转换,可以通过数组的方式指定多个 Loader,并且可以通过
!符号指定 Loader 的执行顺序。
举例来说,以下是一个简单的 webpack 配置,使用了 `babel-loader
9.uglify 原理?
Uglify 是一个 JavaScript 代码压缩工具,它的主要原理是通过删除代码中的空 白符、注释、简化变量名等方式,从而减小代码体积,提高加载速度。Uglify 的原理可以简单概括为词法分析、语法分析和代码压缩三个步骤。
-
词法分析(Lexical Analysis):Uglify 首先对输入的 JavaScript 代码进行词法分析,将代码字符串分割成一系列的 Token(标记),每个 Token 包含了代码中的一个词法单元,如关键字、标识符、运算符等。词法分析器会忽略空格、注释等无关紧要的字符,并为每个 Token 添加对应的类型和值。
-
语法分析(Syntax Analysis):接下来,Uglify 使用语法分析器将 Token 流转换成抽象语法树(AST)。抽象语法树是一个树状结构,它反映了代码的语法结构,每个节点代表了代码中的一个语法单元,如变量声明、函数调用、条件语句等。语法分析器会根据 Token 流的语法规则构建对应的抽象语法树。
-
代码压缩(Code Compression):一旦得到了抽象语法树,Uglify 就可以利用各种代码压缩技术对代码进行压缩。这些压缩技术包括但不限于:
- 删除无效的代码和不可达代码
- 简化变量名和属性名
- 压缩常量和表达式
- 删除注释和空白符
- 合并代码块和语句
- 代码混淆(将变量名、函数
10. babel 原理?
Babel 是一个广泛使用的 JavaScript 编译器,它主要用于将 ECMAScript 2015+ 的代码转换为向后兼容的 JavaScript 版本,以便在现有环境中运行。Babel 的主要原理包括词法分析、语法分析、转换和生成代码四个步骤。
-
词法分析(Lexical Analysis):Babel 首先对输入的代码进行词法分析,将代码字符串分割成一系列的 Token(标记),每个 Token 包含了代码中的一个词法单元,如关键字、标识符、运算符等。词法分析器会忽略空格、注释等无关紧要的字符,并为每个 Token 添加对应的类型和值。
-
语法分析(Syntax Analysis):接下来,Babel 使用语法分析器将 Token 流转换成抽象语法树(AST)。抽象语法树是一个树状结构,它反映了代码的语法结构,每个节点代表了代码中的一个语法单元,如变量声明、函数调用、条件语句等。语法分析器会根据 Token 流的语法规则构建对应的抽象语法树。
-
转换(Transformation):一旦得到了抽象语法树,Babel 就可以利用插件系统对语法树进行转换。Babel 的插件可以对特定的语法结构进行识别和处理,例如箭头函数、解构赋值、类定义等。插件会遍历语法树,对匹配的语法结构进行转换,从而实现对特定语法特性的支持或转换。
-
生成代码(Code Generation):最后,Babel 将转换后的抽象语法树转换回 JavaScript 代码
11. webpack 插件机制?
Webpack 的插件机制是其极为重要的扩展机制之一,通过插件机制可以对Webpack的构建过程进行定制和扩展。在Webpack的构建过程中,插件可以监听Webpack构建生命周期中的各个钩子(Hooks),并且可以访问Webpack的编译实例以及整个构建过程中的各种资源,从而实现对构建过程的干预和定制化处理。
Webpack 插件机制的主要特点包括 :
-
生命周期钩子(Hooks):Webpack 在构建过程中定义了一系列的生命周期钩子,例如
beforeRun、run、emit、afterEmit等。插件可以通过监听这些钩子来介入Webpack的构建过程。 -
编译实例(Compiler)和资源(Compilation):Webpack 插件可以访问Webpack的编译实例和资源,对资源进行修改、分析和优化。编译实例代表了整个Webpack的编译过程,而资源则代表了Webpack正在处理的各种文件和模块。
-
功能扩展和优化:通过编写插件,可以实现对Webpack的功能扩展和优化,例如资源压缩、代码分割、模块分析、自定义输出等。
编写一个Webpack插件通常需要以下步骤:
-
创建一个JavaScript类或函数,该类或函数需要包含一个
apply方法或者是一个符合Webpack插件规范的函数。 -
在
apply方法中,可以访问Webpack提供的编译实例和资源,以及注册对应的生命周期钩子的处理函数。 -
在处理函数中,可以根据需要对资源进行修改或者添加自定义的构建逻辑。
举例来说,一个简单的Webpack插件可能会监听emit钩子,在每次构
12. 白屏怎么优化?
白屏问题通常指的是页面加载时长,用户看到的是空白的页面,而非期望的内容。以下是一些优化白屏问题的方法:
- 代码优化:减少不必要的代码、压缩和合并 JavaScript、CSS 和 HTML 文件,以减少页面加载时间。确保代码精简和高效加载。
- 图片优化:优化图片大小和格式,采用适当的压缩方式,以减少图片加载时间。延迟加载不必要的图片,避免一次性加载大量图片导致页面延迟。
- 异步加载:将不必要的资源加载延迟到页面初次渲染后再进行加载,通过异步加载脚本和资源文件,以加快页面加载速度。
- 代码分割:将页面所需的 JavaScript 代码分割为多个小块,并根据页面需要进行按需加载,以减少初始加载时间。
- 服务端渲染(SSR):对于需要较快的首屏加载的页面,可以考虑使用服务端渲染,以在服务器端生成完整的 HTML 页面,减少客户端渲染时间。
- 浏览器缓存:合理设置静态资源的缓存策略,利用浏览器缓存,减少重复请求,提高页面加载速度。
- 使用预加载和预渲染:通过预加载和预渲染关键资源和页面,以提前加载所需内容,加快页面呈现速度。
- 性能监控和分析:使用工具进行性能监控和分析,及时发现页面加载性能瓶颈,并进行优化。
通过综合运用这些方法,可以有效地优化白屏问题,加快页面加载速度,提升用户体验。
13.动画性能?
要提升动画性能,特别是在 Web 应用程序中,可以采取以下几个方法:
- 使用 CSS 动画:尽量使用 CSS 动画来实现动画效果,而不是使用 JavaScript 来操作 DOM 元素。CSS 动画通常比 JavaScript 动画性能更好,因为它们可以通过 GPU 加速来实现,从而减少 CPU 的负载。
- 使用 transform 和 opacity:在 CSS 动画中,尽量使用
transform和opacity属性来实现 动画效果,因为这两个属性可以通过硬件加速来进行处理,从而提高动画的性能。 - 避免布局抖动:在进行动画设计时,尽量避免频繁地改变元素的布局属性(如宽度、高度、位置等),因为这样会导致页面的布局抖动,降低动画的流畅性。
- 使用 requestAnimationFrame:在 JavaScript 动画中,使用
requestAnimationFrame来执行动画循环,这样可以让浏览器在下一次重绘之前执行动画更新,从而提高动画的性能和流畅度。 - 优化图片和视频:对于包含大量图片或视频的动画,可以优化图片和视频的大小和格式,以减少网络传输和解码的开销,从而提高动画的加载和播放性能。
- 减少重排和重绘:尽量减少对 DOM 结构和样式的修改,因为这会导致页面的重排和重绘,影响动画的性能。可以通过批量处理样式修改、使用文档片段等方式来减少重排和重绘的次数。
- 使用硬件加速:对于复杂的动画效果,可以考虑使用 CSS
- 脱离文档流:对于如何优化动画,我们知道,一般情况下,动画需要频繁的操作 DOM,就就会导致页面的性能问题,我们可以将动画的 **position**属性设置为** absolute**或者** fixed**,将动画脱离文档流,这样他的回流就不会影响到页面了。
14. 渲染合成层?
简单来说,浏览器为了提升动画的性能,为了在动画的每一帧的过程中不必每次都重新绘制整个页面。在特定方式下可以触发生成一个合成层(Composite Layers),合成层拥有单独的 GraphicsLayer。
需要进行动画的元素包含在这个合成层之下,这样动画的每一帧只需要去重新绘制这个 GraphicsLayer 即可,从而达到提升动画性能的目的。
如果我们想尽可能的优化我们的 CSS 动画,或者在日常 CSS 开发中,尽可能的提升 CSS 的性能,这是一个非常重要的概念。通过生成独立的 GraphicsLayer,让此层内的重绘重排不引起整个页面的重绘重排。
这也就是我们常说的,CSS 3D 硬件加速的最本质的原因。
那么一个元素什么时候会触发创建一个 Graphics Layer 层?
从目前来说,满足以下任意情况便会创建层:
-
硬件加速的 iframe 元素(比如 iframe 嵌入的页面中有合成层)
-
硬件加速的插件,比如 flash 等等
-
使用加速视频解码的
-
3D 或者 硬件加速的 2D Canvas 元素
-
3D 或透视变换(perspective、transform) 的 CSS 属性
-
对自己的 opacity 做 CSS 动画或使用一个动画变换的元素
-
拥有加速 CSS 过滤器的元素
-
元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在自己的层里)
-
元素有一个 z-index 较低且包含一个复合层的兄弟元素
因此,通常最为常见的创建一个复合层的方式就是:
-
transform
-
opacity
-
filter(使用频率较低)
我们可以通过合理的使用这几个元素,有效提升页面的性能,譬如使用 transform 代替 left、top,实现位移动画。