破镜Angular(四)Angular性能优化与集成GraphQL

1,570 阅读4分钟

banner窄.png

铿然架构  |  作者  /  铿然一叶 这是铿然架构的第 18 篇原创文章

相关阅读:

萌新快速成长之路
如何编写软件设计文档
JAVA编程思想(一)通过依赖注入增加扩展性
JAVA编程思想(二)如何面向接口编程
JAVA编程思想(三)去掉别扭的if,自注册策略模式优雅满足开闭原则
JAVA编程思想(四)Builder模式经典范式以及和工厂模式如何选?
Java编程思想(七)使用组合和继承的场景
JAVA基础(一)简单、透彻理解内部类和静态内部类
JAVA基础(二)内存优化-使用Java引用做缓存
JAVA基础(三)ClassLoader实现热加载
JAVA基础(四)枚举(enum)和常量定义,工厂类使用对比
JAVA基础(五)函数式接口-复用,解耦之利刃
Seata源码(一)初始化
Seata源码(二)事务基础对象
Seata源码(三)事务处理类结构和流程
Seata源码(四)全局锁GlobalLock
Seata源码(五)Seata数据库操作
Seata源码(六)Seata的undo日志操作
Seata源码(七)Seata事务故障处理
Seata源码(八)Seata事务生命周期hook
Seata源码(九)TCC核心类和处理逻辑
Seata源码(十)RM接收到请求后的调用过程
Seata源码(十一)TC接收到请求后的处理过程\


一、Angular性能优化点

Angular优化只是前端优化的一个子集,本篇仅涉及Angular相关的优化。

1. 合理划分特性模块

在一些项目中所有组件都放到一个模块中,特别是很多组件的初始化逻辑放在组件构造器或者ngOnInit方法中,这样会导致首次加载很慢,而将组件按照相关性划分到不同的特性模块,并使用懒加载方式加载,就能减少首次初始化的时间,提高性能。

2. 选择合适的生命周期钩子

有的时候,我们习惯性的将一些公共方法放到构造器或者ngOnInit方法中,例如给API中心上报组件调用信息,这样也会导致看上去页面首开性能很差,因此,对于不影响界面展现的方法应放到ngAfterViewInit方法中。

3. 按需调用组件初始化方法

当组件包含子组件时,我们会在ngOnInit中调用组件初始化的方法,哪怕这个组件在初次展现时并不可见,例如多个tab页,每个tab页是一个独立的子功能。如果子组件影响了性能,应在子组件可见时再调用初始化方法,而不是放在ngOnInit中。

4. 合并多个服务请求

chrom浏览器对一个域名一次并发的请求数最大是6个,如果超过6个就会排队等待,所以对于超过6个请求的可以考虑合并,合并包括图片合并、js,css文件合并,后端服务合并。一般来说现有的前端框架在打包时已经将js,css文件合并,图片合并和后端服务合并需要自行实现。

二、Angular集成GraphQL

前面提到提高性能的其中一个方法是合并多个服务请求,对此可以要求后端GG重新封装一个聚合服务,通常这也没什么问题,而查询需求可能合并千变万化,当服务很多时总是要求后端GG封装新的聚合服务就不是那么顺利了,为了减少前后端的耦合,可以集成GraphQL来解决这个问题,GraphQL可以在一次查询中同时请求多个后端服务,将多个服务的查询结果聚合后返回。

三、集成样例

这个例子的后端服务参考:Web应用全栈之旅-Spring篇(四)集成GraphQL。

1. 安装apollo-angular

ng add apollo-angular

2. 安装graphql apollo-client相关的的模块

npm install apollo-client apollo-cache-inmemory apollo-angular-link-http apollo-angular graphql-tag graphql  --save

3. 修改连接地址

修改graphql.module.ts中的 uri。

const uri = 'http://localhost:7000/graphql'; // <-- add the URL of the GraphQL server here
export function createApollo(httpLink: HttpLink) {
  return {
    link: httpLink.create({uri}),
    cache: new InMemoryCache(),
  };
}

4. 查询例子(不带变量)

代码如下:

  query() {
    let query = gql`
      query {
        findBook(id:1) {
          name
          publisher
          author{
            id
          }        
        }
        findDogByName(name:"xiaofei") {
          name
          age
          gender
        }
      }
    `;
    
    this.apollo
    .watchQuery({
      query: query,
    })
    .valueChanges.subscribe((result:any)=>{
          console.log(result)
    });
  }

可以看到在一个请求中调用了后端的两个服务。
请求包如下:

{
	"operationName": null,
	"variables": {},
	"query": "{\n  findBook(id: 1) {\n    name\n    publisher\n    author {\n      id\n      __typename\n    }\n    __typename\n  }\n  findDogByName(name: \"xiaofei\") {\n    name\n    age\n    gender\n    __typename\n  }\n}\n"
}

可以看到operationName为null,variables中没有变量传入。
应答包如下:

{
	"data": {
		"findBook": {
			"name": "Java 8实战",
			"publisher": "电子工业出版社",
			"author": {
				"id": 1,
				"__typename": "Author"
			},
			"__typename": "Book"
		},
		"findDogByName": {
			"name": "xiaofei",
			"age": 3,
			"gender": "male",
			"__typename": "Dog"
		}
	}
}

5. 查询例子(带变量)

代码如下:

query1() {
    let query = gql`
      query myoperation($id:Int, $name:String!) {
        findBook(id:$id) {
          name
          publisher
          author{
            id
          }        
        }
        findDogByName(name:$name) {
          name
          age
          gender
        }
      }
    `;
    this.apollo
    .watchQuery({
      query: query,
      variables: {
        id: 1,
        name: "xiaofei",
      },
    })
    .valueChanges.subscribe((result:any)=>{
          console.log(result)
    });

其中myoperation是operationName,可自行定义,目的是为了传入变量。
请求包:

{
	"operationName": "myoperation",
	"variables": {
		"id": 1,
		"name": "xiaofei"
	},
	"query": "query myoperation($id: Int, $name: String!) {\n  findBook(id: $id) {\n    name\n    publisher\n    author {\n      id\n      __typename\n    }\n    __typename\n  }\n  findDogByName(name: $name) {\n    name\n    age\n    gender\n    __typename\n  }\n}\n"
}

可以看到operationName和variables都有值了。

end.

apollographql官网地址: www.apollographql.com/docs/angula…