背景
最近在使用第三方开源组件react-native-echarts-pro(对echarts做了包装,用webview渲染显示)做图表开发时发现了一个问题。
我的项目中使用了大量的formatter函数来做数据的自定义格式化工作,在项目开启Hermes引擎后,那些使用了formatter函数的图表都无法正常显示了。
问题复现
开启Hermes:
project.ext.react = [
entryFile: "index.js",
enableHermes: true, // clean and rebuild if changing
]
echarts option源码:
...
{
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisLabel: {
formatter: (value) => {
return value + '(week)';
},
},
},
yAxis: {
type: 'value'
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line'
}
]
};
echarts运行截图(非正常显示):
问题分析
通过查看Hermes官方库中的issue评论,开启Hermes后,在设备运行代码之前,为了使字节码文件较小并能快速执行,Hermes会编译所有的源码为字节码。当被编译成字节码的formatter函数跟随echarts的option注入到webview中时,是无法被webview正常解析运行的,其toString()方法的返回结果如下图。导致了echarts无法正常渲染显示。
解决方案(不关闭Hermes)
Hermes官方给出的解决方案是在不想被编译成字节码的函数第一行添加代码'show source';
,Hermes遇到到这个标识后就不会把该函数编译成字节码了。我们可以在formatter函数第一行添加代码'show source';
,这样可以保证启用Hermes的同时,formatter函数也能正常被解析。
...
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisLabel: {
formatter: (value) => {
'show source';
return value + '(week)';
},
},
},
...
重新调用formatter函数的toString()结果如下:
其他问题
这里遇到的问题是react native热更新debug模式下,第一次Metro加载或是Metro reload代码后,formatter函数仍是字节码,需要触发一下热更新和echarts的重新渲染,echarts才可以正常显示,formatter函数才会不被编译为字节码。目前暂不清楚原因。
可以先Ctrl + X
移除<echarts />
的代码,然后hot reload,再Ctrl + V
添加上<echarts />
组件的代码,然后再次hot reload,这个时候echarts就正常显示出来了。
打包后执行是完全OK的,没有任何上述问题。
另一个问题是,'show source';
这个特性是在Hermes 0.8.1上添加的,所以需要0.65及以上的react native版本才行。
正常显示效果:
参考连接
https://github.com/facebook/hermes/issues/114#issuecomment-887106990
https://github.com/facebook/hermes/issues/612
https://github.com/supervons/react-native-echarts-pro/issues/35