🐢11s到⚡1s,性能优化之首屏加载🚀

全文共6511字/词,阅读大概须要13分钟,太长不看党请直接移步👉「开始优化」部分直接查看优化手段javascript

背景

前段时间公司服务器网络波动,网站访问变慢,一些性能问题也随之暴露了出来。纷纷反馈在这样的弱网条件下,访问新项目时,加载了近1分钟都没加载出来,而访问其余页面顶多也就30-40s。css

在网络恢复后,尝试访问了下页面,无缓存首次打开须要等待近11s的时间,最大的资源达到了3.7M...html

在对项目作了一些优化处理后,再次无缓存打开能够发现网页几乎是秒开,平均耗时在1s之内前端

在这里总结记录一下,基本上都是一些常规可复制的优化手段,但愿能为一样想优化网页性能的你提供思路~vue

优化效果


Network

Slow3G条件下22-25s加载完成java



lighthouse


hiper

关于性能优化

在开始以前,咱们须要明白一个原则:性能优化的最终目的是提高用户体验
简而言之就是让用户感受这个网站很「快」(至少不慢hh),这里的「快」有两种,一种是「真的快」一种是「以为快」node

  • 「真的快」:能够客观衡量的指标,像网页访问时间、交互响应时间、跳转页面时间
  • 「以为快」:用户主观感知的性能,经过视觉引导等手段转移用户对等待时间的关注

作好这两方面都能提高用户对网站的性能评价。webpack

权衡取舍

另外就是软件工程没有银弹,一种优化方案可能适用于大多数项目,可是某些特殊状况下极可能会起反效果。nginx

举个🌰,因为浏览器有单域名下并发请求限制,一般咱们会将依赖统一打成一个vendor包(vue-cli默认策略),减小首屏请求数,且依赖不变更的状况下文件指纹不变,能够有效利用304缓存。在依赖很少的状况这么处理确实有助于提高加载速度,但一旦依赖多起来,vendor就会特别的大,在弱网条件下,会严重拖慢页面显示。这显然不是咱们想要的,因此咱们根据状况会对vendor进行拆分,好比拆分到CDN,或者直接拆分到页面中git

所以,咱们在作性能优化过程当中,必须根据最终能给用户体验带来的提高权衡后作出适合当前项目的选择

指标和目标

目标会影响咱们在过程当中的决策
指标则用来度量咱们的目标

目标

首先咱们须要肯定目标,根据场景和项目复杂度不一样,制定的目标也不一样,好比但愿比竞品快20%,或者符合标准的"2-5-10"原则等等

这里我定下的目标是

  • 正常网速下,2s内加载完成
  • 弱网下,30s内加载完成

指标

关于指标这块,简单介绍下常见指标

  • FCP(First Contentful Paint):白屏时间(第一个文本绘制时间)
  • Speed Index:首屏时间
  • TTI(Time To Interactive): 第一次可交互的时间
  • lighthouse score(performance):Chrome浏览器审查工具性能评分(也能够npm install -g lighthouse,编程式调用)

调试工具

经过性能调试工具能够直观便捷地获取这些指标,好比Newwork、k六、hiper、Lighthouse...。具体能够看我关于性能调试工具的另外一篇文章

瓶颈分析

Network分析


优化前Network

从Network上咱们发现主要问题在3.2M的chunk-vendor.js上

  • 体积太大,下载慢
  • 阻塞了其余资源下载

Lighthouse分析


优化前Lighthouse

Performance分析

因为本次不涉及到应用内场景性能优化,Performance分析跳过...

dist目录分析

  • 总体体积太大,近5M
  • 出现了若干不该出现的静态资源,好比页面上没引用到SVG图标、应该被内联的小图等
  • 部分图片资源较大,最大的达到仅400KB

Webpack Bundle分析


优化前Bundle

从webpack bundle能够看出,问题着实很多

  • 未剔除项目模板用到的冗余依赖,好比g二、quill、wangEditor、mock等
  • 一些没用到的Ant-design组件因为全局注册也一并打包了进去
  • 项目中只用到几个Ant-Design/icons,但却被全量引入
  • moment和moment-timezone重复,且体积较大
  • core-js体积较大
  • 打包策略不合理,致使chunk-vendor太大

开始优化

🛫🛫🛫

体积优化

⚡排查并移除冗余依赖、静态资源

内容(点击展开/收起)
  • 移除项目模板冗余依赖
  • 将public的静态资源移入assets。静态资源应该放在assets下,public只会单纯的复制到dist,应该放置不经webpack处理的文件,好比不兼容webpack的库,须要指定文件名的文件等等

before:4.96M after:4.12M

⚡构建时压缩图片

内容(点击展开/收起)

每次使用在线服务手动压缩较为麻烦,能够直接在构建流程中加入压缩图片

使用image-webpack-loader

// install
npm i image-webpack-loader -D
// vue.config.js
chainWebpack: (config) => {
    if (isProd) {
        // 图片压缩处理
        const imgRule = config.module.rule('images')
        imgRule
            .test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
            .use('image-webpack-loader')
            .loader('image-webpack-loader')
            .options({ bypassOnDebug: true })
            .end()
    }
}
复制代码
  1. install或build时若是出现imagemin库下载失败,能够尝试 换源、配置github hosts、install时添加--user=root解决
  2. 因为在图片下载后已经手动用在线工具压缩过,这部分提高不大

before:4.12M after:4.00M

⚡使用webP图片

内容(点击展开/收起)

webP是谷歌推出的新图片格式(2010),同等质量下体积拳打png脚踢jpg,目前兼容性还算能够,就苹果家的表现不太理想

转换为webP图片

能够手动,也能够加入构建自动化生成。

  • 手动,可使用webP-converter、智图等工具,但建议使用官方webP-converter,除了便捷性,同质量下体积各方面均优于智图。
./cwebp -q 75 login_plane_2.png -o login_plane_2.webp
复制代码
  • 自动化生成,可使用image-min-webp或其余webpack插件

页面中使用(兼容低版本)

  • HTML中使用,<picture>标签兼容
<picture>
    <source srcset="hehe.webp" type="image/webp">
    <img src="hehe.png" alt="hehe>
</picture>
复制代码
  • CSS中使用,须要配合JS作判断
// main.js
window.addEventListener('DOMContentLoaded', () => {
    const isSupportWebP = document.createElement('canvas')
    .toDataURL('image/webp')
    .indexOf('data:image/webp') === 0
    document.documentElement.classList.add(isSupportWebP ? '' : '.no-support-webp');
})
// css
.support-webp .bg{
    background-image: url("hehe.webp");
}

.no-support-webp .bg {
    background-image: url("hehe.png");
}
复制代码
  1. 请务必使用原图进行webp转换,不然会影响体积
  2. 项目大图很少,最大400KB的图片转换后只有48.9KB

⚡优化SVG图标

内容(点击展开/收起)

这一步咱们来优化部分冗余的旧SVG图标被打包进去的状况,通常项目中SVG使用方式都是在iconfont生成JS而后引入。这种作法

  • 不直观,每次都得去iconfont复制名称使用
  • 每次增删改图标须要从新替换整个JS
  • 不能按需加载,没使用到的也会一块儿打包,特别是UI换图标时通常不会将旧图标删除....
  • 添加自定义SVG不友善,必须上传iconfont添加到一块儿再下载

更优的SVG玩法

  • 新增/修改图标
    • 在iconfont下载UI上传或者其余地方找的任意SVG图标放入icons/svg/下
    • 页面中使用全局svg组件,传入复制下SVG的文件名便可
  • 删除
    • 只须要去掉使用的地方,而后删除对应图标便可

要实现上述效果,只须要

  • 引入svg-sprite-loader
// install
npm i svg-sprite-loader -D
// vue.config.js
chainWebpack: (config) => {
    // SVG处理
    config.module
      .rule('svg')
      .exclude.add(resolve('src/icons/svg'))
      .end()
    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(resolve('src/icons/svg'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })
      .end()
    
}
复制代码
  • 建立src/icons/svg并将图标放进去,并经过webpack的require.context自动导入
// src/icons/index.js
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)

// main.js
import '@/icons'
复制代码
  • 建立全局组件ca-svg
// src/icons/index.js
import Vue from 'vue'
import CaSVG from '@/components/ca-svg'
Vue.component('ca-svg', CaSVG)

// src/components/ca-svg.vue
<template>
  <svg :class="svgClass" aria-hidden="true" v-on="$listeners" :style="svgStyle">
    <use :xlink:href="iconName" />
  </svg>
</template>
...
// name属性为必须字段,其余size或color能够自由定制
复制代码

压缩优化

SVG一般会有一些冗余信息致使影响体积,这里咱们可使用svgo-loader来进一步压缩

// install
npm i svgo-loader -D

// vue.config.js
// 接上面svg的配置
...
.end()
.use('svgo-loader')
.loader('svgo-loader')
.end()
复制代码

⚡优化Ant-design-vue体积

内容(点击展开/收起)

能够看到这部分在chunk-vendor中占的比例不小

按需引入

这部分实际上已是作了处理的了,具体操做参考ant-design-vue文档,按说明作没啥大坑,效果也符合预期。

快速上手 - Ant Design Vue

删除冗余组件

部分组件是不常常用的,但却使用了Vue.use()全局引入了。这里去掉不经常使用和没用到的全局引入,改成页面内import()引入

⚡优化Ant-design-icon体积

内容(点击展开/收起)

这一部分,因为咱们在项目中只使用了几个Ant内置图标,不可能有530+KB。根据Ant文档的描述是因为其将ICON全量引入的关系致使的,说法是当前用法若是按需加载的话没法肯定使用者会不会在运行时改变icon,好比配置的ICON。

重定向到本地来控制

这个问题,在React版的Ant-Design是已是作了处理的了(写法上有所调整),但在Ant-Design-Vue-1.x中仍然没有官方解决方案。目前了解到的有两种方案

  • 使用webpack-ant-icon-loader (异步加载)
  • 重定向到本地文件来控制 (推荐),使用alia将将@ant-design/icons/lib/dist指向项目中的antd-icon.js,而后在antd-icon中按需导出便可
// alias配置
resolve: {
  alias: {
    '@ant-design/icons/lib/dist$': path.resolve(__dirname, './src/icons/antd-icon.js')
  }
}
// src/icons/antd-icon.js
export { default as LoadingOutline } from '@ant-design/icons/lib/outline/LoadingOutline'
复制代码
  1. 注意项目中和Ant组件中使用的ICON都要导出
  2. 优化后从530K+到30K+

⚡优化moment、moment-timezone体积

内容(点击展开/收起)

这两个包300K + 160K,加起来有460K,也是占的比较多的一项

不打包moment时区文件

这里使用内置的IgnorePlugin便可作到

// webpack plugins
plugins: [
  // Ignore all locale files of moment.js
  new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
复制代码

移除moment-timezone

moment-timezone包含了moment,项目中只有一处地方使用到,用来获取东八区的当前时间,moment是能够作到的,不须要额外引入moment-timezone

// old
moment.tz('Asia/Shanghai').format('YYYYMMDDHHmmss')
// new
moment.utcOffset(480).format('YYYYMMDDHHmmss')
复制代码

使用dayjs替代moment

dayjs实现了moment的大多数功能,Api基本一致,压缩后体积却不到2k,是优秀的替代方案,且多数状况下,dayjs能够完美的替代moment(按需引入插件)

可是这里遇到了使用Ant-Design的第二个坑,Ant-Design实现Date-Picker时使用了moment,因此在项目中不使用moment也无论用,同样会打包进来....

这个问题,在React版的Ant-Design又已是作了处理的了,容许用户选择dayjs或moment。一样的,Ant-Design-Vue仍没有跟进...

所幸,dayjs做者提供了一个插件,能够将Ant-Design-Vue的moment替换成dayjs👍 虽然文档中只说Ant-Design-React能够用,但实际上在issue能够看到它也适用于antdV,不过须要调整一些配置

使用antd-dayjs-webpack-plugin

// vue.config.js
const AntdDayjsWebpackPlugin = require('antd-dayjs-webpack-plugin')
configureWebpack: {
    ...
    plugins: [
      new AntdDayjsWebpackPlugin({ preset: 'antdv3', replaceMoment: true })
    ],
}
复制代码

replaceMoment参数是用webpack alias来重定向moment到dayjs,因为项目中多处使用moment,这样作能够继续使用moment实际上调用的dayjs,实现无感知替换👍

  1. 替换成dayjs后,一些功能须要经过引入插件来保持一致,好比utc、updateLocale
  2. 替换成dayjs后,一些针对moment的优化须要改为dayjs或去掉

⚡优化core-js体积

内容(点击展开/收起)

core-js实际上就是浏览器新API的polyfill,项目是PC端,因此主要是为了兼容IE...

调整.browserslistrc

  • 指定项目须要兼容的版本,让babel和auto-prefix少作点兼容性工做,好比移动端不用兼容IE、iOS6.0如下等等

调整useBuiltIns

项目中默认是useBuiltIns: 'entry'将全部polyfill都引入了,致使包比较大。咱们可使用useBuiltIns: 'entry'调整下策略,按需引入,项目中没使用到的API就不作polyfill处理了

// babel.config.js
module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset',
    [
      '@babel/preset-env',
      {
        'useBuiltIns': 'usage', // entry,usage
        'corejs': 3
      }
    ]
  ],
  plugins
}
复制代码

btw,这里更优的作法应该是使用动态polyfill,让服务器根据UA判断是否要返回polyfill

before:4.96M after:2.96M


传输优化

⚡优化分包策略

内容(点击展开/收起)

vue-cli3的默认优化是将全部npm依赖都打进chunk-vendor,但这种作法在依赖多的状况下致使chunk-vendor过大

optimization: isProd ? {
  splitChunks: {
    chunks: 'all',
    maxInitialRequests: Infinity, // 默认为3,调整为容许无限入口资源
    minSize: 20000, // 20K如下的依赖不作拆分
    cacheGroups: {
      vendors: {
        // 拆分依赖,避免单文件过大拖慢页面展现
        // 得益于HTTP2多路复用,不用太担忧资源请求太多的问题
        name(module) {
          // 拆包
          const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1]
          // 进一步将Ant组件拆分出来,请根据状况来
          // const packageName = module.context.match(/[\\/]node_modules[\\/](?:ant-design-vue[\\/]es[\\/])?(.*?)([\\/]|$)/)[1]
          return `npm.${packageName.replace('@', '')}` // 部分服务器不容许URL带@
        },
        test: /[\\/]node_modules[\\/]/,
        priority: -10,
        chunks: 'initial'
      }
    }
  },
  runtimeChunk: { name: entrypoint => `runtime-${entrypoint.name}` }
} : {}
复制代码
  1. Tips: vue inspect > output.js --mode production 能够查看最终配置
  2. 分包这块须要根据实际状况作对应处理,才能取得比较好的效果,总之多看文档多试就对了

⚡优化路由懒加载

内容(点击展开/收起)

SPA中一个很重要的提速手段就是路由懒加载,当打开页面时才去加载对应文件,咱们利用Vue的异步组件和webpack的代码分割(import())就能够轻松实现懒加载了。

但当路由过多时,请合理地用webpack的魔法注释对路由进行分组,太多的chunk会影响构建时的速度

{
    path: 'register',
    name: 'register',
    component: () => import(/* webpackChunkName: "user" */ '@/views/user/register'),
}
复制代码

请只在生产时懒加载,不然路由多起来后,开发时的构建速度感人

⚡开启HTTP2

内容(点击展开/收起)

HTTP2是HTTP协议的第二个版本,相较于HTTP1 速度更快、延迟更低,功能更多。 目前来看兼容性方面也算过得去,在国内有超过50%的覆盖率。

一般浏览器在传输时并发请求数是有限制的,超过限制的请求须要排队,以往咱们经过域名分片、资源合并来避开这一限制,而使用HTTP2协议后,其能够在一个TCP链接分帧处理多个请求(多路复用),不受此限制。(其他的头部压缩等等也带来了必定性能提高)

若是网站支持HTTPS,请一并开启HTTP2,成本低收益高,对于请求多的页面提高很大,尤为是在网速不佳时

Nginx开启HTTP2(>V1.95)

  • 调整Nginx配置
// nginx.conf
listen 443 http2;
复制代码
  • 重启Nginx
nginx -s stop && nginx
复制代码
  • 验证效果

HTTP2开启后

多路复用避开了资源并发限制,但资源太多的状况,也会形成浏览器性能损失(Chrome进程间通讯与资源数量相关)

⚡Gzip压缩传输

内容(点击展开/收起)

Gzip压缩是一种强力压缩手段,针对文本文件时一般能减小2/3的体积。

HTTP协议中用头部字段Accept-EncodingContent-Encoding对「采用何种编码格式传输正文」进行了协定,请求头的Accept-Encoding会列出客户端支持的编码格式。当响应头的 Content-Encoding指定了gzip时,浏览器则会进行对应解压

通常浏览器都支持gzip,因此Accept-Encoding也会自动带上gzip,因此咱们须要让资源服务器在Content-Encoding指定gzip,并返回gzip文件

Nginx配置Gzip

#开启和关闭gzip模式
gzip on;
#gizp压缩起点,文件大于1k才进行压缩
gzip_min_length 1k;
# gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间
gzip_comp_level 6;
# 进行压缩的文件类型。
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript ;
# nginx对于静态文件的处理模块,开启后会寻找以.gz结尾的文件,直接返回,不会占用cpu进行压缩,若是找不到则不进行压缩
gzip_static on
# 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;
# 设置gzip压缩针对的HTTP协议版本
gzip_http_version 1.1;
复制代码

构建时生成gzip文件

虽然上面配置后Nginx已经会在响应请求时进行压缩并返回Gzip了,可是压缩操做自己是会占用服务器的CPU和时间的,压缩等级越高开销越大,因此咱们一般会一并上传gzip文件,让服务器直接返回压缩后文件

// vue.config.js
const CompressionPlugin = require('compression-webpack-plugin')
// gzip压缩处理
chainWebpack: (config) => {
    if(isProd) {
        config.plugin('compression-webpack-plugin')
            .use(new CompressionPlugin({
                test: /\.js$|\.html$|\.css$/, // 匹配文件名
                threshold: 10240, // 对超过10k的数据压缩
                deleteOriginalAssets: false // 不删除源文件
            }))
    }
}
复制代码
  1. 插件的默认压缩等级是9,最高级的压缩
  2. 图片文件不建议使用gzip压缩,效果较差

⚡Prefetch、Preload

内容(点击展开/收起)

<link>标签的rel属性的两个可选值。
Prefetch,预请求,是为了提示浏览器,用户将来的浏览有可能须要加载目标资源,因此浏览器有可能经过事先获取和缓存对应资源,优化用户体验。
Preload,预加载,表示用户十分有可能须要在当前浏览中加载目标资源,因此浏览器必须预先获取和缓存对应资源。

Prefetch、Preload能够在某些场景下能够有效优化用户体验。 举些场景

  • 首屏字体、大图加载,CSS中引入字体须要等CSS解析后才会加载,这以前浏览器会使用默认字体,当加载后会替换为自定义字体,致使字体样式闪动,而咱们使用Preload提早加载字体后这种状况就好不少了,大图也是如此
  • 优惠券的背景图加载,一样CSS中url引用在DOM没挂载以前是不会加载图片的,进入卡包页/收银台时能够提早使用Prefetch加载,这样用户在进行优惠券页就能够立马看到加载完成的图片了

Vue-Cli3默认会使用preload-webpack-plugin对chunk资源作preload、prefetch处理,入口文件preload,路由chunk则是prefetch。

通常来讲不须要作特别处理,若是判断不须要或者须要调整在vue.config.js中配置便可

  1. 理论上prefetch不会影响加载速度,但实际测试中,是有轻微影响的,不过这个见仁见智,我认为整体体验上仍是有所提高的,
  2. 相似字体文件这种隐藏在脚本、样式中的首屏关键资源,建议使用preload
  3. 移动端流量访问时慎用

⚡托管至OSS + CDN加速

内容(点击展开/收起)

当应对一些弱网地区时,OSS + CDN无疑是很强力的提速手段。

OSS,对象存储

海量,安全,低成本,高可靠的云存储服务。能够经过简单的REST接口,在任什么时候间、任何地点上传和下载数据,也可使用WEB页面对数据进行管理。

OSS的特色:

  • 稳定,服务可用性高,多重备份保障数据安全
  • 安全,多层次安全防御,防DDoS
  • 大规模,高性能,从容应对高并发

另外,OSS还提供一些方便的服务

  • 图片处理,支持压缩、裁剪、水印、格式转换等
  • 传输加速,优化传输链路和协议策略实现高速传输

这里推荐直接购买阿里家的OSS,OSS虽然也有传输加速服务,但对于静态热点文件的下载加速场景仍是须要CDN加速

CDN,内容分发网络

CDN加速原理是把提供的域名做为源站,将源内容缓存到边缘节点。当客户读取数据时,会从最适合的节点(通常来讲就近获取)获取缓存文件,以提高下载速度。

因为没申请到资源,项目并无上OSS+CDN。但若是有条件仍是建议上,提高很大


感知性能优化

😎白屏时的loading动画

内容(点击展开/收起)

首屏优化,在JS没解析执行前,让用户能看到Loading动画,减轻等待焦虑。一般会在index.html上写简单的CSS动画,直到Vue挂载后替换挂载节点的内容,但这种作法实测也会出现短暂的白屏,建议手动控制CSS动画关闭

😎首屏骨架加载

内容(点击展开/收起)

首屏优化,APP内常见的加载时各部分灰色色块。针对骨架屏页的自动化生成,业界已有很多解决方案。


感知优化的一些补充

首屏之外的一些场景优化,更多相关内容好比图片懒加载、组件懒加载等 后续文章会作介绍

😎渐进加载图片

内容(点击展开/收起)

通常来讲,图片加载有两种方式,一种是自上而下扫描,一种则是原图的模糊展现,而后逐渐/加载完清晰。前者在网速差的时候用户体验较差,后者的渐进/交错式加载则能减轻用户的等待焦虑,带来更好的体验

渐进/交错格式图片

浏览器自己支持这种图片的模糊到清晰的扫描加载方式,只须要将处理好资源便可

  • UI生成,PS导出选择「连续」,Sketch导出选择「渐进/交错」
  • 转换,使用第三方库处理

渐进加载图片

先加载小图,模糊化渲染,图片加载完成后替换为原图,最典型的例子就是Medium,模糊化能够用filter或者canvas处理

加载占位图

先加载全局通用loading图或者用CSS填充色块,图片加载完成后替换为原图。简单粗暴,在弱网条件下颇有用

  1. 几种方式能够同时搭配使用
  2. 渐进/交错格式图片会占用必定CPU和内存,酌情使用

😎路由跳转Loading动画

内容(点击展开/收起)

弱网优化手段,用了懒加载后用户若是在弱网条件下点击下一个页面在下个页面加载完成前页面内容不可用,用户会理解为卡顿。 在VueRouter的路由守卫中处理便可

结尾

本文只介绍了首屏加载场景下的性能优化,实际上性能优化远不止这些内容,SPA的加载性能指标采集光靠Lighthouse、slow 3G模拟真的可信吗?除了加载场景外的其余方面呢?构建速度、操做流畅性...

业务

性能优化影响的,不只是用户体验,还影响了转化率、搜索引擎排名,这些因素都会对最终的流量、销量等收入形成影响

来自Google的数据代表,一个有10条数据0.4秒能加载完的页面,变成30条数据0.9秒加载完以后,流量和广告收入降低90%。

Google Map 首页文件大小从100KB减少到70-80KB后,流量在第一周涨了10%,接下来的三周涨了25%。

亚马逊的数据代表:加载时间增长100毫秒,销量就降低1%。

立场不一样,看问题角度也会变化,好比对老板来讲最终目的实际上是搞钱hh,用户体验这些花里胡哨的,别人不必定懂。


用户体验 × money √

因此若是必要,请在过程先后作好性能收益的数据监控和分析,在性能优化和产品指标之间创建正向联系,方便自上而下的推进技术方案的执行。这才是你说服上司或领导投入成本到性能优化上的重要依据

我的提高

性能优化算是老生常谈的话题了,但部分人在面对怎么作性能优化的问题时,仅仅只是罗列出各类常见优化手段,更有深度的答案应该是遇到什么性能问题,针对这个问题围绕某些性能指标采起了什么手段,手段是否带来了其余问题,怎么权衡,最终达到了什么样的效果。

参考

相关文章
相关标签/搜索