H5W3
当前位置:H5W3 > HTML5 > 正文

股票交易APP频繁更新前端性能优化

写本文的原因

  • 有几位小伙伴最近又来问这个问题,之前帮人解答过一次,今天写下来
  • 以后有时间会多写一些解决方案,例如oom了,不用esbuild怎么解决之类的等..

正式开始

主题:股票交易APP(IM场景前端交互高频更新卡顿)

  • 一个正常的股票交易APP,是很复杂的,大都用原生写,但是有的公司没钱啊,只能做一套web app或者用RN这些写,也有用Flutter的(这就是没钱又要玩,那怎么办呢?那就玩乞丐版呀)

一个股票交易APP的界面长这样

  • 首先金融交易类产品是IM产品的一种,大都使用私有基于TCP长链接私有协议或者wss协议,这里推荐两篇我之前写的文章,这样你来看本文效果会比较好。
    • 手写实现一个websocket协议(基于Node.js)
    • 手写一个React框架

问题重现

  • 用户收藏了1000只自选股(国内国外+期货+指数等),技术栈是web app ,基于react或React-native,很卡顿
  • 由于是双工通讯,而且高频推送,触发更新,而且交易类APP对消息送达的效率/低延迟要求非常高,例如你准备买这只股票,此时大户砸盘,你还没收到更新的信息,下单,发现趋势已经走坏,然后接盘被套。
  • 还有一种情况,你买入的时候出了大利好,你下单价格是10块钱,但是此时已经涨到10.05,这个价格成成交不了,然后你错过了一波大涨。这时候客户就惨了

需求简单&技术的剖析

  • 理论上用户可以添加的自选股票,是无限的
  • 每个自选股/股票的都有对应的事件触发

  • 高频更新,此时要区分react/react-native环境,因为react-native组件在挂载后就不会卸载了,不像web app.

原则

  • 性能优化最好是简单的手段
  • 所见即所得,简单高校,不触碰底层逻辑,例如网络层前后端可能都要做粘包的处理
  • …不做可能诱发P0级别事故的技术方向选择

解决问题

  • react/react-native渲染上有区别,对于长列表,react-native是有组件对应只渲染可视区域,react则不会,需要虚拟列表,推荐react-peter-window这个库,而且可以支持自动高宽

源码demo地址:https://github.com/JinJieTan/react-keepAlive-dynamic

  • 这样react也可以跟react-native的组件一样,只渲染可视区域了
  • 长列表问题解决了,但是事件同时也很麻烦,理论上用户可以添加无限的自选股,这个列表可能就有无限长(不要说不可能,世界在发展,这就是高可用的APP),传统的事件需要每个item去绑定,然后切换组件时候再remove掉,但是频繁对事件挂载、移除其实也很损耗性能,这里换成事件冒泡,就可以了,把需要的数据挂载到dom的属性上获取即可~
  • 上面说的,不要小看,能解决相当一部分性能问题

最重要的高频更新的问题

  • 不同金融交易类公司,后端架构设计不一样,消息推送也是,例如大智慧的后端架构就比较特殊.
  • 前端网络层可能要处理粘包,后端的消息推送频率我们不管
  • 借鉴PReact、Redis、kafka的思想,自己在前端实现一个消息队列,定期消费,更新界面.
  • 参考我之前手写React的代码:

`https://github.com/JinJieTan/mini-react/tree/hooks
import { _render } from '../reactDom/index';
import { enqueueSetState } from './setState';
export class Component {
constuctor(props = {}) {
this.state = {};
this.props = props;
}
setState(stateChange) {
const newState = Object.assign(this.state || {}, stateChange);
console.log(newState,'newState')
this.newState = newState;
enqueueSetState(newState, this);
}
}` 
  • 当setState后,先进入队列中,首次进入,队列为空,进入判断,下一帧渲染前调用defer(flush)
`export function enqueueSetState(stateChange, component) {
//第一次进来肯定会先调用defer函数
if (setStateQueue.length === 0) {
//清空队列的办法是异步执行,下面都是同步执行的一些计算
defer(flush);
}
//向队列中添加对象 key:stateChange value:component
setStateQueue.push({
stateChange,
component,
});
//如果渲染队列中没有这个组件 那么添加进去
if (!renderQueue.some((item) => item === component)) {
renderQueue.push(component);
}
}` 
  • defer函数
`function defer(fn) {
//高优先级任务 异步的 先挂起
return requestAnimationFrame(fn);
}` 
  • 此时消息再次推送,再次触发enqueueSetState,数据此时被推送到队列中,一帧统一合并消费。

本文地址:H5W3 » 股票交易APP频繁更新前端性能优化

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址