钉钉红包性能优化之路 - 实践

news/2025/10/5 19:44:09/文章来源:https://www.cnblogs.com/ljbguanli/p/19126950

钉钉红包性能优化之路 - 实践

一、业务背景

请客红包、小礼物作为饿了么自研的业务产品,在钉钉的一方化入口中常驻,作为高UV、PV的toB产品,面对不同设备环境的用户,经常会偶尔得到一些用户反馈,如【页面白屏太久了】、【卡住了】等等,本文将以产品环境为出发点(App中的H5),以前端基础、加载链路、端能力三个方向进行性能优化。

基于现阶段业务架构,在应用层进行通用的性能优化action拆解。

整体优化后接近秒开,效果如下:
请添加图片描述

二、前端基础优化

2.1. 构建产物瘦身

作为前端基础优化的出水口,可通过webpack analyzer插件分析dist产物的具体分布,主要action如下:

关键优化代码:

// case1:按需引入大npm包
import setTitle from '@ali/dingtalk-jsapi/api/biz/navigation/setTitle'
;
import openLink from '@ali/dingtalk-jsapi/api/biz/util/openLink'
;
import setScreenKeepOn from '@ali/dingtalk-jsapi/api/biz/util/setScreenKeepOn'
;
// case2:externals拆包,转cdn引入
externals: {
react: 'React'
,
'react-dom': 'ReactDOM'
,
}
// case3:图片裁剪,降低质量、大小降低图片请求耗时
import getActualSize from './getActualSize'
;
import getImageType from './getImageType'
;
const getActualEleImageUrl = (url: string
, size: number
) =>
{
if (
typeof url === 'string' && url.includes('cube.elemecdn.com'
)
) {
const imageType = getImageType(url)
;
const relSize = getActualSize(size)
;
const end = `?x-oss-process=image/resize,m_mfit,w_${relSize
},h_${relSize
}/format,${imageType
}/quality,q_90`
;
return `${url
}${end
}`
;
}
return url;
}
;
// case4:按需加载antd-mobile
extraBabelPlugins: [
[
'import'
,
{
libraryName: 'antd-mobile'
,
libraryDirectory: 'es/components'
,
}
,
]
,
]
,

结果:

  • 性能优化构建包gzip压缩后大小减少305.59KB,优化后大小474.74KB,下降39.1%;
  • 性能优化首屏加载冷启动FP减少400ms,热启动FP减少1s;

2.2. 预加载&预解析

将应用中所用到的所有请求资源的能力统一前置配置在html head,减少所有资源类请求的耗时。

links: [
{
rel: 'dns-prefetch'
,
href: 'https://g.alicdn.com/'
,
}
,
{
rel: 'preconnect'
,
href: 'https://g.alicdn.com/'
,
}
,
{
rel: 'dns-prefetch'
,
href: 'https://gw.alicdn.com/'
,
}
,
{
rel: 'preconnect'
,
href: 'https://gw.alicdn.com/'
,
}
,
{
rel: 'dns-prefetch'
,
href: 'https://img.alicdn.com/'
,
}
,
{
rel: 'preconnect'
,
href: 'https://img.alicdn.com/'
,
}
,
{
rel: 'dns-prefetch'
,
href: 'https://assets.elemecdn.com/'
,
}
,
{
rel: 'preconnect'
,
href: 'https://assets.elemecdn.com/'
,
}
,
{
rel: 'dns-prefetch'
,
href: 'https://static-legacy.dingtalk.com/'
,
}
,
{
rel: 'preconnect'
,
href: 'https://static-legacy.dingtalk.com/'
,
}
,
{
rel: 'dns-prefetch'
,
href: 'https://cube.elemecdn.com/'
,
}
,
{
rel: 'preconnect'
,
href: 'https://cube.elemecdn.com/'
,
}
,
{
rel: 'preload'
,
as: 'script'
,
href: 'https://g.alicdn.com/??/code/lib/react/18.2.0/umd/react.production.min.js,/code/lib/react-dom/18.2.0/umd/react-dom.production.min.js'
,
}
,
]
,

2.3 分包

到的所有请求在整个项目中以页面组件、公共组件、大npm包三个方向进行分包拆解,大体分包策略是尽可能减少SPA首次访问路由的chunk体积,策略如下:

分包关键代码:

optimization: {
moduleIds: 'deterministic'
, // 确保模块id稳定
chunkIds: 'named'
, // 确保chunk id稳定
minimizer: [
new TerserJSPlugin({
parallel: true
, // 开启多进程压缩
extractComments: false
,
}
)
,
new CssMinimizerPlugin({
minimizerOptions: {
parallel: true
, // 开启多进程压缩
preset: [
'default'
,
{
discardComments: {
removeAll: true
}
,
}
,
]
,
}
,
}
)
,
]
,
splitChunks: {
chunks: 'all'
,
maxAsyncRequests: 5
, // 同时最大请求数
cacheGroups: {
// 第三方依赖
vendors: {
test: /[\/]node_modules[\/]/
,
name(module) {
const packageName = module.context.match(/[\/]node_modules[\/](.*?)([\/]|$)/
)[1]
;
return `vendor-${packageName.replace('@'
, ''
)
}`
;
}
,
priority: 20
,
}
,
// 公共组件
commons: {
test: /[\/]src[\/]components[\/]/
,
name: 'commons'
,
minChunks: 3
, // 共享模块最少被引用次数
priority: 15
,
reuseExistingChunk: true
,
}
,
lib: {
// 把node_modules里面大于160kb的模块拆分成单独的chunk
test(module) {
return (
module.size(
) >
160 * 1024 &&
/node_modules[/\]/.test(module.nameForCondition(
) || ''
)
)
;
}
,
// 把剩余的包打成一个chunk
name(module) {
const packageNameArr = module.context.match(/[\/]node_modules[\/](.*?)([\/]|$)/
)
;
const packageName = packageNameArr ? packageNameArr[1] : ''
;
return `chunk-lib.${packageName.replace('@'
, ''
)
}`
;
}
,
priority: 15
,
minChunks: 1
,
reuseExistingChunk: true
,
}
,
// 默认配置
default: {
minChunks: 2
,
priority: 10
,
reuseExistingChunk: true
,
name(module, chunks) {
const allChunksNames = chunks.map((item) => item.name).join('~'
)
;
return `common-${allChunksNames
}`
;
}
,
}
,
}
,
}
,
}
,

三、加载链路优化

3.1 DOM load前置优化

在SPA所有JS文件解析完成(整个页面呈现),在前置可增加loading态替代白屏减少用户的等待焦虑,具体的思路是在html response -> js chunk全部解析完成中间,增加一个loading状态,提升FP、FCP性能指标,具体行动是编写了一个webpack html构建完的插件,在构建结果中的html手动注入loading组件。

插件实现比较简单:

import {
IApi
}
from 'umi'
;
export
default (api: IApi) =>
{
// 用于在html ready到SPA应用js ready之间增加钉钉标准loading
api.modifyHTML(($) =>
{
$('head'
).prepend(`
<style>body, html {width: 100%;height: 100%;margin: 0;padding: 0;border: 0;box-sizing: border-box;}#html-ding-loading-container {width: 100vw;height: 100vh;background: rgba(0, 0, 0, 0.2);opacity: 1;}#ding-loading {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);animation: lightningAnimate 1s steps(1, start) infinite;width: 3.6rem;height: 3.6rem;background-repeat: no-repeat;background-position: 0rem 0rem;background-size: 100%;background-image: url('https://img.alicdn.com/imgextra/i4/O1CN014kqXkX22y9iy5WhI6_!!6000000007188-2-tps-120-3720.png');}@keyframes lightningAnimate {0% { background-position: 0rem 0rem; }3.3% { background-position: 0rem calc(-1 * 3.6rem); }6.6% { background-position: 0rem calc(-2 * 3.6rem); }10% { background-position: 0rem calc(-3 * 3.6rem); }13.3% { background-position: 0rem calc(-4 * 3.6rem); }16.6% { background-position: 0rem calc(-5 * 3.6rem); }20% { background-position: 0rem calc(-6 * 3.6rem); }23.3% { background-position: 0rem calc(-7 * 3.6rem); }26.6% { background-position: 0rem calc(-8 * 3.6rem); }30% { background-position: 0rem calc(-9 * 3.6rem); }33.3% { background-position: 0rem calc(-10 * 3.6rem); }36.6% { background-position: 0rem calc(-11 * 3.6rem); }40% { background-position: 0rem calc(-12 * 3.6rem); }43.3% { background-position: 0rem calc(-13 * 3.6rem); }46.6% { background-position: 0rem calc(-14 * 3.6rem); }50% { background-position: 0rem calc(-15 * 3.6rem); }53.3% { background-position: 0rem calc(-16 * 3.6rem); }56.6% { background-position: 0rem calc(-17 * 3.6rem); }60% { background-position: 0rem calc(-18 * 3.6rem); }63.3% { background-position: 0rem calc(-19 * 3.6rem); }66.6% { background-position: 0rem calc(-20 * 3.6rem); }70% { background-position: 0rem calc(-21 * 3.6rem); }73.3% { background-position: 0rem calc(-22 * 3.6rem); }76.6% { background-position: 0rem calc(-23 * 3.6rem); }80% { background-position: 0rem calc(-24 * 3.6rem); }83.3% { background-position: 0rem calc(-25 * 3.6rem); }86.6% { background-position: 0rem calc(-26 * 3.6rem); }90% { background-position: 0rem calc(-27 * 3.6rem); }93.3% { background-position: 0rem calc(-28 * 3.6rem); }96.6% { background-position: 0rem calc(-29 * 3.6rem); }100% { background-position: 0rem calc(-30 * 3.6rem); }}
</style>

`
)
;
$('body'
).prepend(`
<div id='html-ding-loading-container'>
<div id='ding-loading'></div>
</div>

`
)
;
}
)
;
}
;
// 在umi中注入
plugins: [
'@umijs/plugins/dist/initial-state'
,
'@umijs/plugins/dist/model'
,
'./plugins/loading.ts'
,
]
,

实现效果:

在这里插入图片描述

3.2 session管理持久化

系统中在前端资源全部response解析完成后,对所有的业务接口请求执行前都需要确保getUserInfo接口响应成功并在前端接收sessionId,然后在所有的业务接口中携带在参数中,在系统交互链路的前置流程过长的背景下,前端基于storage实现getUserInfo数据持久化从而节省一次关键串行接口的请求。

在这里插入图片描述

关键用户信息读取的代码:

import getCurrentUserInfo$ from '@ali/dingtalk-jsapi/api/internal/user/getCurrentUserInfo'
;
export
async
function fetchUserInfo(
) {
const dingUid =
await getCurrentUserInfo(
)
;
let storageUserInfo = getUser(
)
;
let res: UserDto;
if (storageUserInfo &&
+dingUid?.uid === +storageUserInfo?.dingUserId) {
// 如果缓存中的用户信息是当前用户,使用缓存
res = {
userType: 'dingtalkUid'
,
userId: storageUserInfo.dingUserId,
userName: storageUserInfo.nick,
name: storageUserInfo.nick,
mobile: storageUserInfo.mobile,
avatarUrl: storageUserInfo.avatarUrl,
}
;
window.enjoyDrinkTrace.logError('命中storageUserInfo缓存'
)
;
}
else {
// 未命中缓存,走请求用户信息流程
const corpId = getQueryString('corpId'
)
;
const userInfo =
await getUserInfo({
corpId,
userChannel: getQueryString('__from__'
) || ''
,
}
)
;
res = {
userType: 'dingtalkUid'
,
userId: userInfo.data.data?.userID,
userName: userInfo.data.data?.userName,
name: userInfo.data.data?.userName,
mobile: userInfo.data.data?.mobile,
avatarUrl: userInfo.data.data?.avatarUrl,
}
;
}
return res;
}

这一步优化在FP节点之后,减少了与FCP中间的耗时,减少量为一次接口请求的时间,约100ms。

四、做好基本的,再借助一下端能力

4.1 离线策略

做好前端基本的优化+H5加载链路的优化后结合cdn自带的缓存,整体的首屏用户体验已经很不错了。

那如native般的秒开,怎么实现?由于业务运行在钉钉中,咨询了钉钉同学,对于产品首页、红包页等页面布局不大的场景中尝试接入离线。

结合实际业务场景,在请客红包中,所有资源都可根据离线预置到App本地,在用户访问页面时,可以尽早为页面渲染铺垫;此外还可以推送相应的 js 缓存文件,减少 js 下载时长,让用户可交互时间提前;页面中的固定图片,也可以通过 zcache 缓存,提升页面图片整体的缓存命中率。

结合了所有的优化后,请客红包的IM消息主入口基本做到秒开。

请添加图片描述

五、未来规划

结合各类性能优化的手段,沉淀出相对应的代码、文档、prompt、tools等,集成到agent中,在未来的相关新产品设计中,让业务在起步阶段就有相对应稳定、体验较好的体感。

基于ARMS性能插件、钉钉容器性能监控看板,持续提升业务性能,保障业务用户体验。

对于场景投放类页面(目前是MPA多页方案),后续考虑转SSR

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/928657.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQLite详细解读 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

IIS反向代理tomcat

由于我的网站是IIS搭建的,而某些项目必须使用Tomcat进行部署,所以就有了这次实践。主要解决以下问题问题1:IIS和tomcat的2各网站使用的端口不同,但是希望使用二级域名来访问,而不是通过端口号来访问问题2:不希望…

2025混合机厂家最新企业品牌推荐排行榜,高效盘条式混合机,无重力混合机,犁刀式混合机,锥形混合机,卧式螺带混合机推荐这十家公司!

在粉体设备行业中,混合机作为关键设备,其性能与质量直接影响着众多下游产业的生产效率与产品品质。当前,市场上混合机品牌数量众多,产品种类繁杂,质量参差不齐,给企业的选购带来了诸多困扰。一些品牌的混合机存在…

2025离心泵厂家最新企业品牌推荐排行榜! 卧式离心泵,化工离心泵,多级离心泵,卧式多级离心泵,不锈钢离心泵推荐这十家公司!

在工业领域中,离心泵作为流体输送的关键设备,广泛应用于化工、石油、电力、冶金等诸多行业。然而,随着市场的不断发展,离心泵制造商如雨后春笋般涌现,产品质量与技术水平参差不齐。如何在众多制造商中挑选出技术先…

Axure-元件流程图 - 指南

Axure-元件&流程图 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco"…

2025真空炉厂家最新企业品牌推荐排行榜,高温烧结真空炉,真空退火炉,智能铍铜真空炉推荐这十家公司!

在工业生产领域,真空炉作为关键的热处理设备,其性能与质量直接影响着众多行业的生产效率与产品品质。随着工业 4.0 的深入推进以及半导体、5G 通信、航空航天等高端产业的快速发展,市场对真空炉的需求日益增长,同时…

【论文阅读】Dolphin: Document Image Parsing via Heterogeneous Anchor Prompting - 实践

【论文阅读】Dolphin: Document Image Parsing via Heterogeneous Anchor Prompting - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !import…

2025 --【J+S 二十连测】-- 第二套 总结

总结 T1 T2 T3 很快就写出来了,没什么大问题。 T4 T5 没有写出来,下来有个非常巧妙的思路。 题解 T1 我们只需要横纵坐标最小的,最大的那些点。然后把它们全部照在一起,那就可以了。 代码 #include<bits/stdc++…

2025 蒸发器厂家最新企业品牌推荐排行榜,江苏纵横携手知名品牌,彰显蒸发器公司行业影响力

在当前的工业生产领域,蒸发器作为重要的设备,广泛应用于食品发酵、化工、医药、环保等多个行业。然而,市场上蒸发器厂商数量众多,产品质量参差不齐,技术水平也存在较大差异,给企业在选购时带来了诸多困扰。部分厂…

如何将 WSL 的 Ubuntu-24.04 迁移到其他电脑 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

题解:Luogu P11976 [KTSC 2021] 通信网络 / communication

一些约定 下文中的 \(x\) 的祖先,都指位于 \(\bm{fa_x}\) 到根节点路径上的点(也就是不包括 \(x\))。 对于无向图 DFS 生成树中的一条返祖边,我们称深度较浅的那端为上端点,深度较深的那端为下端点。 题意 对于一…

弦振动方程

弦振动方程 参考:https://chat.deepseek.com/a/chat/s/36c8bd34-0600-4a94-be96-8363d028df9d

理论构建尝试整理

通过脑机接口的电信号实时训练神经网络模型 研究方向:生成式认知主体 导论: 自从1947的 但至少在我看来现如今的人工智能发展方向完全是走错了路线 根据图灵测试的逻辑来讲 著名的图灵测试诞生,按照“人工智能之父”…

应用安全 --- 安卓安全 之 调用隐藏

应用安全 --- 安卓安全 之 调用隐藏可能会将调用的so中方法写入jnionload中动态注册同时将函数字符串加密存储这个问题很常见,有几种可能的原因。让我帮你分析一下: 可能的原因和解决方案 1. 函数名被混淆或压缩bash…

电子商城网站开发平面广告设计素材网

PTA 排队“夹塞”是引起大家强烈不满的行为&#xff0c;但是这种现象时常存在。在银行的单窗口排队问题中&#xff0c;假设银行只有1个窗口提供服务&#xff0c;所有顾客按到达时间排成一条长龙。当窗口空闲时&#xff0c;下一位顾客即去该窗口处理事务。此时如果已知第i位顾客…

淘宝客网站哪个好克隆视厅网站怎么做

人工智能和芯片供应商 XMOS 宣布与嵌入式音频软件专家 DSP Concepts 建立合作伙伴关系。该合作协议将允许音频开发人员将 XMOS 的高度确定性、低延迟的 xcore.ai 平台与 DSP Concepts 的 Audio Weaver 软件结合起来。该软件使用户能够利用多核算力以图形方式设计和调试音频和语…

商城网站开发视频邯郸网站设计邯郸网站制作

简介&#xff1a; 《实时数仓入门训练营》由阿里云研究员王峰、阿里云资深技术专家金晓军、阿里云高级产品专家刘一鸣等实时计算 Flink 版和 Hologres 的多名技术/产品一线专家齐上阵&#xff0c;合力搭建此次训练营的课程体系&#xff0c;精心打磨课程内容&#xff0c;直击当下…

2025聚合硫酸铁厂家最新企业品牌推荐排行榜,工业聚合硫酸铁,混凝剂聚合硫酸铁,固态聚合硫酸铁,粉末聚合硫酸铁,硫酸亚铁公司推荐!

当前聚合硫酸铁行业发展迅速,市场上生产厂家数量众多,但质量参差不齐,给采购方带来诸多选择难题。部分厂家存在生产工艺落后、产品纯度不足的问题,导致其生产的聚合硫酸铁在水处理等应用场景中效果不佳,不仅影响水…

2025成型机厂家最新企业品牌推荐排行榜,冷弯成型机,卷帘门成型机,卷闸门成型机,彩钢瓦成型机,货架成型机推荐!

在当前金属加工行业快速发展的背景下,冷弯成型机作为关键生产设备,其质量与性能直接影响企业的生产效率和产品品质。然而,市场上成型机厂家数量众多,实力参差不齐,给企业选购带来诸多困扰。部分厂家缺乏核心技术,…

基于springboot的家政服务预约系统 - 指南

基于springboot的家政服务预约系统 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "…