开发者社区 > 博文 > 详解ROMA中复杂图表的渲染实现
分享
  • 打开微信扫码分享

  • 点击前往QQ分享

  • 点击前往微博分享

  • 点击复制链接

详解ROMA中复杂图表的渲染实现

  • jd****
  • 2025-10-14
  • IP归属:北京
  • 22浏览

    一、背景

          ROMA承接很多复杂图表的渲染需求,在京东金融APP内,特别是首页首屏的图表,对图表渲染的及时性要求很高。近期业务反馈频繁重启时,首页的黄金走势图偶现渲染不出的问题,通过梳理图表的渲染流程,对缓存策略、视图加载和渲染过程进行了重构,确保渲染成功率,提升了渲染速度以及补充了异常重试的功能。

    二、使用场景分析

          京东金融App内有很多使用复杂图表的业务场景,以下截取部分场景。下图分别是黄金历史金价的走势图、用户购买的基金的收益走势图、小金库的收益柱状图、用户投资诊断的雷达图、省钱账单和AI助手账单趋势柱状图。

          可见,金融App内图表的使用具备种类丰富、数据信息量大,定制程度高、交互频繁等特点,经调研发现,Apache ECharts 是一个基于 JavaScript 的功能强大的开源可视化图表库,被广泛应用于数据分析、监控系统、报表工具等领域。并且支持定制支持的图表类型,可降低图标库的体积和提升图标库的加载速度。由于原生端并没有类似的图表库,因次决定在 ROMA 中引入 ECharts 来承接复杂图表的显示需求 。

    三、重构过程分析

    1、原理分析

          ROMA 对外提供 echarts 标签,内部依赖提前加载了 echarts.js 库的 WebView,将图表数据交给准备好环境的 webveiw,达到渲染图表的目的。这里有一个重要的前提就是成功加载了echarts.js 库的 WebView 才具备快速渲染各类图表的能力。并且需要提前打通 ROMA 与 Native,Native 与 WebView 之间的数据通讯,保证数据在三端之间的顺畅流转。

         为此自定制了 JRTransEchartsWebView 专门用于渲染 echarts 数据,JRTransEchartsComponent 作为标签实现在承接 webview 和 jue 环境的数据传递和业务逻辑处理。以下类图展示了各主要类对象之间的相互关系。      

          首先打通 Native 和 WebView 的数据交互,原生端在创建 WebView 的时候就向其环境中注入 window 的 message 事件监听,拦截指定类型的事件,获取从 WebView 环境中发来的数据。

    NSString *jsStrring = @"window.addEventListener('message', (e) => { \
                            var customDict = {'function':'jdttransWindowEventDispatch',\ 
                                              'careParamDict':{'data': e.data, 'origin': e.origin}};\ 
                            window.webkit.messageHandlers.JDTTransEchartsHandler.postMessage(customDict);})";
    NSString *jscode = [NSString stringWithFormat:jsStrring];
    WKUserScript *script = [[WKUserScript alloc]initWithSource:jscode injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
    [webView.configuration.userContentController addUserScript:script];

          Native 向 WebView 发送数据通过 evaluateJavaScript 的方式,向JS环境中输入数据:

    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{@"type":@"message"}]; 
    [dict jdd_setObjectCheck:message forKey:@"data"]; 
    [dict jdd_setObjectCheck:@"*" forKey:@"origin"]; 
    NSString *dictString = [dict jdd_JSONString]; 
    NSString *jsString = [NSString stringWithFormat:@"javascript:(function (){ \
                                                      var event = new MessageEvent('message', %@);\ 
                                                      window.dispatchEvent(event);})()",dictString]; 
    [webView evaluateJavaScript:jsString completionHandler:nil];

          JUE 和 Native 之间的通讯通道在初始化 ROMA 的 SDK 时就已经建立,Native 和 webview 的数据交互也通过 postMessage 的方式建立,如下图所示:

         

          以上,JUE 通过调用 call native 将数据发送到 Native,Native 通过 window.dispatchEvent 的方式将数据传递给 WebView。而图表上的手势交互等事件 WebView 通过 postMessage 的方式发送,在 Native 监听指定类型的 message 获取数据,通过处理并通过 fire event 触发到 JUE。

    2、缓存的设计

          对于 echarts 渲染图表数据,大致经历以下过程,创建 webview,加载 echarts.js 渲染库,资源开始加载 ,资源成功加载,最后渲染图表数据,这几个过程中,除了最后一步渲染数据,前面的步骤都可以提前做,越早完成前面的工作,越能提升图表渲染的效率。

           为此,设计了可重复利用的并可自动扩容的 WebView 缓存容器 JRTransEchartsCache。在App启动阶段缓存 min 个 WebView 保存至缓存列表 cacheArray 中,并持续跟踪 WebView 加载 echarts.js 的阶段,确保在成功加载了 echarts.js 资源后再开始渲染图表数据。而对于过早的图表渲染指令,则先保存至指定标签的指令缓存列表 eventArray 中,待成功加载后,再渲染 eventArray 中的数据。

          而对于 WebView 加载 echarts.js 资源失败的情况,也加入了失败重试的逻辑,当业务端发起数据渲染时会检查环境状态,而触发 echarts.js 的重新加载。

          随着 WebView 使用,其状态被标记为 using,并根据使用的情况,自动触发 cacheArray 中的 WebView 扩容,最大扩容至 max 个。对于从详情页返回而释放的图表,其 WebView 将会被标记为 free ,可提供为其他的图表视图使用。 当使用图表的业务持续增多,当 cacheArray 中的 WebView 都被使用后,则新创建的 WebView 不再加入 cacheArray,遵循当次获取,当次创建,使用完成,就地销毁的原则。

    3、渲染流程

          下图记录了从 App 启动到业务创建 echarts 图表,到业务退出,到 App 退出期间,融合了缓存的初始化以及自动扩容,包括在 webview 加载 echarts.js 资源的不同阶段对渲染指令的处理,以及视图销毁后的内存处理等场景下的处理流程。

    四、效果验证

          为了更直观的展示图表在业务上的使用场景,使用重构后的图表标签渲染柱状图、条形图、折线图、饼图和组合图表,渲染的效果和操作都很流畅(由于文档的限制,对以下视频做了降频和清晰度的处理),效果如下:

    五、总结

          通过此次图表的重构,在App冷启时,以 iPhoneXS Max 设备为例,首页首屏渲染图表数据的时间平均缩短了200ms;冷启首页首屏图表的渲染成功率,由之前的平均90%提升至接近100%;非首页首屏的图表渲染几乎零延迟;对于异常情况导致的环境初始化失败的问题,也在接受渲染指令时自检渲染环境并重启环境初始化,自动恢复数据的渲染。如果你也对图表渲染或者对跨端框架 ROMA 感兴趣,可留言交流。