woodpecker 性能

检查运行时性能

检查pecker.oa.com, Performance 和 Memory面板

运行时性能未发现明显问题

在页面上点击交互, 切换路由, 查询, 内存占用平稳. 检查Memory标签未发现明显内存泄漏问题.
图中上方帧数降低主要出现在在页面触发submit事件后大规模重新计算样式与重排时.

运行时性能还不错, 主要优化方向集中在打包, 加载与网络优化.

文件加载优化

目前打包size图

来看这个图, 可以看到chunk.js 在 gziped 后单文件太大, 占了 1.2Mb. 三五百kb的大小应该比较合理.

最左侧的antd必须引入. 而图中间一列, recharts和highcharts也占了不小的空间, moment的国际化也占了不小.

大js带来的问题是下载单文件与解析会变慢, 见图:


通过Lighthouse的测试, FCP 略慢 (超过2s). 上图说明此文件在本机上的执行所用CPU时间占了1.2秒. 应缩减此js文件大小.

目前应该先不用太在意Skipping Effects: 指 React.memo, useEffect, PureComponent, shouldComponentUpdate, redux 这种运行时性能优化.

当前打包出来的大 js-bundle, 没有做代码拆分, 初次打开得等下载解析完才会加载出页面, 比较影响性能。

考虑使用 React.lazy + Suspense

React.lazy方法是内置的code-splitting工具, 可以像渲染一个普通组件那样去渲染一个动态引入组件. 可以方便地将独立的组件分离为单独的js-chunk.

// 修改前
import OtherComponent from './OtherComponent';
// 修改后
const OtherComponent = React.lazy(() => import('./OtherComponent'));

第一次渲染这个组件时, 这个方法将自动加载包含OtherComponent的js-bundle, React.lazy结合动态import相应的js会被webpack拆分, 在使用时才加载. React.lazy接受个函数, 函数中必须调用一个动态import(), 动态import()会返回一个Promise, 这个Promis会"resolve"出一个export default React组件的 module.

这种用 lazy() 加载的组件, 可以渲染在Suspense组件中, 通过fallback属性, 可以方便的去管理它loading时, 以及加载失败时要展示的组件:

import React, { Suspense } from 'react';

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
}

因此大概从下面三个方向进行动态 import

1. 路由懒加载

老生常谈的路由懒加载. 在项目中的路由部分使用lazy也比较合理, 因为浏览传统网站的逻辑就是点击链接时要等待一定时间来加载. 下方是一个例子.

import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Switch>
        <Route exact path="/" component={Home}/>
        <Route path="/about" component={About}/>
      </Switch>
    </Suspense>
  </Router>
);

另一个例子

function lazyload(loader: () => Promise<{ default: React.ComponentType<any> }>) {
  const LazyComponent = React.lazy(loader)
  const Lazyload: React.FC = (props: any) => {
    return (
      <React.Suspense fallback={<Spinner/>}>
        <LazyComponent {...props}/>
      </React.Suspense>
    )
  }
  return Lazyload
}

const Login = lazyload(() => import('src/pages/Home'))

不过现在有一个问题, 我们用的路由是 rsf 中的 ConfigRouters, 其中的Route组件中的属性值是用变量使用的, 但动态import不允许使用变量.

2. React 组件懒加载

使用这几个工具可以更轻松地从组件层面对进行代码进行拆分.
下面是一个使用了 React.lazy 但没用 Suspense 的例子

import React, { lazy } from 'react';

const AvatarComponent = lazy(() => import('./AvatarComponent'));

const DetailsComponent = () => (
  <div>
    <AvatarComponent />
  </div>
)

这里有个将React.lazySuspense结合起来的演示: react-lazy-suspense, 打开开发者工具可以看到, 当点了 Click Me 按钮后, 会加载要展示组件单独的js文件.

目前的想法是将 CommonPage 组件中, 除了QueryForm, 下方查询的 Container 部分用这种方法处理.

3. 第三方库与本地文件懒加载

对于某些引入的不太常用的第三方js, 可用import()在用到时动态加载

async function encrypt(value: string): Promise<string> {
  // 改为 import() 的方式引入第三方库
  const module = await import('jsencript')
  // expor default 导出的模块
  const JSEncrypt = module.default
  // 配合引入的 JSEncrypt 加密
  const encrypt = new JSEncrypt()
  encrypt.setPublicKey(PUBLIC_KEY)
  const encrypted = encrypt.encrypt(value)
  return encrypted
}

这可以用来懒加载项目中的 JSON 文件等,通过 import() 方式懒加载的代码或者 JSON 文件,同样会经过 webpack 处理, 例如项目中用到了存储展示状态的大号JSON文件, 就可以像这样动态导入:

const module = await import('./errorStatus.json')
console.log(module.default)

项目中用到的high-chartrecharts, 应该是比较适用于这种处理方式, 但这种已经被封装在shared-component中的该如何懒加载? 这俩第三方库占的空间不小了, 懒加载对于提升首屏加载速度应该效果明显.

参考链接:
react code splitting
reactlazy官方文档

http/2

服务器目前在用http/1.1, 启用 http/2 应该会加快多个请求资源的速度. 不过现在查询接口较慢, 查询条件又比较灵活, 接口侧不太容易做优化. 配置方式:

Nginx

server {
    listen 443 http2;
    server_name xxx.xxx;
}

moment优化

我们可能不需要加载整个moments, 比如moment/locale/*.js中的国际化文件, 除了英语和zh-cn可以都不要
可以借助webpack.ignorePlugin排除.

new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),

Webpack官网此插件的介绍就是用moment举例的: Webpack-ignore-plugin

lodash优化

其实lodash占得空间并不大, 优化后减小文件效果应该不会很明显, 稍微带过.
保证引入时为

import debounce from 'lodash/debounce'

而不是

import lodash from 'lodash'
// 或者
import { debounce } from 'lodash'

即可.

image.png
image.png
image.png
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345