寻找真凶Echarts or Angular
寻找真凶Echarts or Angular这是一篇故事,就如同技术,我们所追求的不是一个结局,而是那些深受启发与共鸣的过程,那是我们成长的经验与生产力的积淀! 故事开始于“疯了”的ionic3应用页面打开,什么也没做5s里angular的代码似乎一直在跑! 打开chrome性能调试工具,recorded 5秒,密密麻麻的调用栈,惨不忍睹! Qustion1:难道真凶是angular脏检查,发生了循环脏检查??要弄清这个问题前,我们先来介绍angular脏检查这个大人物。 Rape1:angular2及以上版本脏检查方式新一代的angular一改angularjs(ng1)中受人唾弃的脏检查策略。 数据流的改变angularjs的策略::是again and again直到稳定。也就是说在异步事件触发脏检查后,脏检查发生过程中某一个scope值改变后,会再次触发一次脏检查直到scope上数据稳定不变。这样一个过程很难找到一次脏检查是哪一次、哪一个对象发生改变导致的dom更新。 谁告诉angular做脏检查的改变angularjs的方式: 注入ng事件来通知脏检查,例如,你不能在js原生的setTimeout里改变model值,必须注入ng事件$setTimeout。 Qustion2:是不是从组件树顶向下逐一组件进行脏检查,会不会是组件树太庞大log了太多checked,执行了太多次单个组件脏检查? Rape2: angular脏检查策略
先来看看现场,上面的图中圈出了一段代码changeDetection: ChangeDetectionStrategy.OnPush,它是做什么的呢?它可以改变脏检查的策略。上面提到一颗组件树中某一个节点某个event触发了脏检查,整棵组件树每一个节点都会跟着做脏检查对吧?对的,默认的策略是这样的。但angular可以更聪明点,使用OnPush策略。这个策略会让该个组件在input对象引用指针没发生变化时跳过该节点及该节点子节点脏检查(注意:是对象引用指针的变化)。 @Component({ selector: 'echart',template: `<div class="charts" #root></div>`,changeDetection: ChangeDetectionStrategy.OnPush }) export class ChartComponent { @Input('option') option: any; constructor() { } ngOnInit(): void { window.addEventListener('resize',this.resize,true); } click():void{ this.option= { title:'hi' } } resize() { this.option.title = 'Hi' } } 这个例子中,当页面窗口发生变化是resize中修改title,,dom不会有任何更新。如下图:
而当click方法触发时,该组件会进行脏检查并更新dom。 如果使用了OnPush策略,又想让resize中的修改能能更新dom怎么办?代码如下 constructor(private ref: ChangeDetectorRef) {} resize() { this.option.title = 'Hi' this.ref.markForCheck(); } 依然是从上到下,angular会找到包含的路径的所有component进行逐一脏检查(及时顶层组件设置了onPush策略)如下图: answer2:很显然组件树庞大不会引起脏检查多,因为我们已经加了onPush策略,input也未改变,该组件及该组件向下的组件都不应该发生脏检查 我们再来看一下调用栈,如下图:
从图中我们发现了一个调用栈NgZone的代码执行过,还记得Rape1里提到NgZone吗?发起脏检查的通知者,它代理了原生事件,任何一个原生异步事件的触发都会导致NgZone的运行。那么一定是有原生事件在一直Loop执行! 【注:细心的人可能还发现图里有一些同学会发现有angular.core的代码在执行,不是在answer2中已经说了不会脏检查了吗?确实不会在做脏检查,rape2中也说明过脏检查策略的原理,别忘了再脏检查前还会check组件input引用来决定是否该组件做脏检查呢】 Qustion3:谁在调戏NgZone?
look this!果然有一个requestAnimationFrame定时器()原生事件一直在执行,且从未销毁! answer3:原来流氓是echarts的animation.js或者说是echarts核心组件zrender在动画结束后没调用animation中的stop方法,总之真凶是echarts! 凶手找到了,受害者还需要安抚解决,如何解决?弃用echarts?你要知道有一种流氓叫让你讨厌又让你干不掉,不得不承认echarts的绘制效率在移动端还是不错的,还有地图,用其它chart plugin谁来给你画某某市地图... export class EChartsComponent implements OnInit,OnDestroy { @Input() chartid: string; @Input('option') option: any; private chart: any; @ViewChild('root') private root; constructor(private ngZone: NgZone) { } resizeListener = () => this.resize(); ngOnInit(): void { this.ngZone.runOutsideAngular(() => { this.chart = echarts.init(this.root.nativeElement); this.chart.setOption(this.option,true); window.addEventListener('resize',this.resizeListener,true); }) } } 优化后5s内perfermance如图:
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |