Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在Angular应用中使用echart,会持续占用cpu #7047

Closed
hpyou opened this Issue Nov 15, 2017 · 15 comments

Comments

Projects
None yet
6 participants
@hpyou
Copy link

hpyou commented Nov 15, 2017

One-line summary [问题简述]

echart在Angular里面使用,会持续占用cpu,这是性能图:

image

主要是触发了AnimationFrame:

image

通过callstack查询到这个函数会持续调用:

image

对应的echart里的代码:
image

主要是Animation对象里的_startLoop函数里有个递归调用step,并且self._running一直是true,这使得step一直会被调用。这在Angular的zone会触发变更检查,导致占用cpu。一般一张图会占用8、9个点。

image

Version & Environment [版本及环境]

  • ECharts version [ECharts 版本]: 3.5.4
  • Browser version [浏览器类型和版本]: chrome 60.0.3112.101(正式版本) (32 位)
  • OS Version [操作系统类型和版本]: win7

Expected behaviour [期望结果]

页面无操作时,不应该占用cpu

ECharts option [ECharts配置项]

option = {

}

Other comments [其他信息]

@hpyou

This comment has been minimized.

Copy link
Author

hpyou commented Nov 15, 2017

Related issue #2886

@Ovilia

This comment has been minimized.

Copy link
Contributor

Ovilia commented Nov 15, 2017

@hpyou 所以跟 Angular 环境没什么关系是吧?我后面会看下

@hpyou

This comment has been minimized.

Copy link
Author

hpyou commented Nov 15, 2017

@Ovilia 是的,我在一个新的html里面引用echart也会有这样的问题,只是在Angular的zone里面性能消耗更明显一点。

@rdkmaster

This comment has been minimized.

Copy link

rdkmaster commented Nov 15, 2017

@hpyou 把你测试的html文件给贴到这里,麻烦 @Ovilia 看看。

这个问题和angular没有任何关系。

@rdkmaster

This comment has been minimized.

Copy link

rdkmaster commented Nov 15, 2017

@Ovilia 当页面上只有少数几个图的时候,看不出区别,但是当一个页面上很多图(我们的一个页面有30个echart图)的时候,浏览器进程就把cpu吃满了。

@Ovilia

This comment has been minimized.

Copy link
Contributor

Ovilia commented Nov 15, 2017

@rdkmaster 图片类型有什么特殊的吗?还是每种都会有?

@hpyou

This comment has been minimized.

Copy link
Author

hpyou commented Nov 15, 2017

@Ovilia 我用是饼图,

echart代码用npm包里的echarts\dist\echarts.js ,版本是3.5.4。

这是html页面:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="height:400px"></div>
<!-- ECharts单文件引入 -->
<script src="echarts.js"></script>
<script type="text/javascript">
    var myChart = echarts.init(document.getElementById('main'));
    var option = {
        title : {
            text: '某站点用户访问来源',
            subtext: '纯属虚构',
            x:'center'
        },
        tooltip : {
            trigger: 'item',
            formatter: "{a} <br/>{b} : {c} ({d}%)"
        },
        legend: {
            orient : 'vertical',
            x : 'left',
            data:['直接访问','邮件营销','联盟广告','视频广告','搜索引擎']
        },
        toolbox: {
            show : true,
            feature : {
                mark : {show: true},
                dataView : {show: true, readOnly: false},
                magicType : {
                    show: true,
                    type: ['pie', 'funnel'],
                    option: {
                        funnel: {
                            x: '25%',
                            width: '50%',
                            funnelAlign: 'left',
                            max: 1548
                        }
                    }
                },
                restore : {show: true},
                saveAsImage : {show: true}
            }
        },
        calculable : true,
        series : [
            {
                name:'访问来源',
                type:'pie',
                radius : '55%',
                center: ['50%', '60%'],
                data:[
                    {value:335, name:'直接访问'},
                    {value:310, name:'邮件营销'},
                    {value:234, name:'联盟广告'},
                    {value:135, name:'视频广告'},
                    {value:1548, name:'搜索引擎'}
                ]
            }
        ]
    };

    // 为echarts对象加载数据
    myChart.setOption(option);

</script>
</body>
</html>
@hpyou

This comment has been minimized.

Copy link
Author

hpyou commented Nov 16, 2017

@Ovilia 在Angular中有个变更检查机制,会在每个异步操作和事件触发后检查组件树。在echart中如果不停的触发Animation Frame,就会导致Angular不停的检查组件树。如果组件树很庞大,就会占用很多cpu。

Angular每次执行变更检查,会在组件中执行ngDoCheck钩子:
image

在控制台中可以看到不停的打印:
image

@hpyou

This comment has been minimized.

Copy link
Author

hpyou commented Nov 20, 2017

@Ovilia Hi~, my friend
我研究了requestAnimationFrame的相关问题。requestAnimationFrame相对于setTimeout是不一样的,不管执行多少requestAnimationFrame,网页的AnimationFrame事件永远只会有一个,也就是不管有多少张图,页面的cpu占用只会有1、2个点,这对性能的影响可以忽略不计的。
我们这边也用了一个方法,将echarts运行到了Angular Zone之外,AnimationFrame触发变更检查的问题得到了解决。
谢谢,麻烦了。

@Ovilia Ovilia closed this Nov 20, 2017

@Ovilia Ovilia removed the pending label Nov 20, 2017

@rdkmaster

This comment has been minimized.

Copy link

rdkmaster commented Nov 20, 2017

这个问题是另一个典型的angular的change detection机制与传统前端库的冲突例子,建议echart可以将这个解决方法放到你们的faq里,让在angular中使用echart的其他同学不掉这个坑。
类似的问题Jigsaw已经碰到过个了

@Ovilia

This comment has been minimized.

Copy link
Contributor

Ovilia commented Nov 20, 2017

@rdkmaster 谢谢建议

@liwenda122

This comment has been minimized.

Copy link

liwenda122 commented Nov 24, 2017

@rdkmaster 扯,还典型例子

@yy7054wyq5

This comment has been minimized.

Copy link

yy7054wyq5 commented Jul 26, 2018

@hpyou 你好,有个问题想和你交流一下,希望你有空的时候回复一下。请问你将echart置于zone之外后,那生成的图表是不受zone监控的。那么仅仅是展示的话应该是没问题的。若是有数据交互的话,那不是很麻烦了?

@hpyou

This comment has been minimized.

Copy link
Author

hpyou commented Jul 26, 2018

@yy7054wyq5 有数据交互,用zone.run放到zone里面跑,确保echarts.init在zone之外就行

@yy7054wyq5

This comment has been minimized.

Copy link

yy7054wyq5 commented Jul 26, 2018

@hpyou 谢谢解惑。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.