詳解ROMA中復雜圖表的渲染實現
一、背景
ROMA長期負責多種復雜圖表的渲染任務,尤其在京東金融APP中首頁首屏等關鍵位置,對渲染的及時性與穩定性有極高要求。近期業務反饋,在APP頻繁重啟的場景下,首頁圖表偶現渲染失敗的情況。為此,我們系統梳理了圖表的完整渲染流程,并對緩存策略、視圖加載與渲染鏈路進行了整體重構。在保障渲染成功率的基礎上,進一步提升了渲染速度,并新增了異常狀態下的自動重試機制。
二、使用場景分析
京東金融App內有很多使用復雜圖表的業務場景,以下截取部分場景。下圖分別是黃金歷史金價的走勢圖、用戶購買的基金的收益走勢圖、小金庫的收益柱狀圖、用戶投資診斷的雷達圖、省錢賬單和AI助手賬單趨勢柱狀圖。
圖片
可見,金融App內圖表的使用具備種類豐富、數據信息量大,定制程度高、交互頻繁等特點,經調研發現,Apache ECharts是一個基于JavaScript的功能強大的開源可視化圖表庫,被廣泛應用于數據分析、監控系統、報表工具等領域。并且支持定制支持的圖表類型,可降低圖標庫的體積和提升圖標庫的加載速度。由于原生端并沒有類似的圖表庫,因次決定在ROMA中引入ECharts來承接復雜圖表的顯示需求 。
三、重構分析過程
1. 原理分析
ROMA 對外提供echarts標簽,內部依賴提前加載了echarts.js庫的WebView,將圖表數據交給準備好環境的WebView,達到渲染圖表的目的。這里有一個重要的前提就是成功加載了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];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資源的不同階段對渲染指令的處理,以及視圖銷毀后的內存處理等場景下的處理流程。
圖片
四、效果驗證
為了更直觀的展示圖表在業務上的使用場景,使用重構后的圖表標簽渲染柱狀圖、條形圖、折線圖、餅圖和組合圖表,渲染的效果和操作都很流暢(由于文檔的限制,對以下視頻做了降頻和清晰度的處理),效果如下:
圖片
五、總結
通過此次圖表的重構,以iPhoneXS Max設備為例,在App冷啟時的首頁首屏渲染圖表數據的時間平均縮短了200ms;冷啟首頁首屏圖表的渲染成功率由之前的平均90%提升至近100%;非首頁首屏的圖表渲染幾乎零延遲;對于異常情況導致的環境初始化失敗的問題,也在接受渲染指令時自檢渲染環境并重啟環境初始化,自動恢復數據的渲染。






























