保藏本站 保藏本站
188bet注册网主页 - 软件测验 - 常用手册 - 站长东西 - 技能社区
主页 > JavaScript > JavaScript技巧 > 正文

主页 - PHP - 数据库 - 操作体系 - 游戏开发 - JS - Android - MySql - Redis - MongoDB - Win8 - Shell编程 - DOS指令 - jQuery - CSS款式 - Python - Perl

Access - Oracle - DB2 - SQLServer - MsSql2008 - MsSql2005 - Sqlite - PostgreSQL - node.js - extjs - JavaScript vbs - Powershell - Ruby

浅析Angular2子模块以及异步加载

用Angular2开发一个大型的运用,咱们一般都需求分模块进行开发。例如将某一个功用的相关页面和功用放在一个模块里边,这样既可以完成体系的松耦合,给开发和后期的保护带来很大的便当。一同,关于子模块,咱们还可以运用延时加载,这样可以削减初始加载的文件的巨细。在这篇文章中,咱们就来看看在Angular2结构下怎样完成子模块及其延时加载。

可以在这儿检查本文运用的实例 。该实例依据上篇文章Angular2运用Guard和Resolve进行验证和权限操控 所用的实例,并在它根底上添加了一个lazy的模块,以及将现有的todo模块装备成延时加载办法。

为了表现启用延时加载前后的包的巨细改变,以及启用紧缩后的改变,在这个教程里边,运用了angular-cli创立项目脚手架,并用它来进行测验和打包。有关angular-cli的运用请检查 官网 。在这篇文章咱们运用的angular-cli的版别是1.0.0-beta.21。假如你运用的是其他版别,或许成果就会不一样。乃至有些过错,咱们在终究会阐明当时版别angular-cli的bug。

模块规划

在开发Angular2运用时,像组件规划、路由规划以外,关于一个较大型的运用,咱们还需求规划模块。例如,将一个运用分红几个功用模块,以及有哪些共用模块。共用模块里边应该放共用的service类,例如权限验证、登录、获取用户信息、大局的过错处理、东西类等,还有封装的指令或组件。而在某一个功用模块里边,只处理这个模块里边的事务,尽量不好其他模块交互。

拿之前教程中的TodoList运用来说,只需home页面和2个todo页面,咱们把todo相关的功用放在一个子模块里边,为了演示,又加了一个简略的名字叫lazy的模块。咱们将把todo模块和lazy模块装备成延时加载的模块。

子模块开发

接下来再看看子模块的开发。其实在之前的比如中,就把todo相关的组件放在了一个模块里边。可是却没有着重子模块开发需求留意的当地,乃至有些装备或许没有选用子模块的办法进行装备。这儿,咱们就首要阐明一下需求留意的当地,假如要检查完好的代码,请参阅 实例源代码 。

子模块路由

首要需求留意的是路由。在之前的比如中,咱们把todo相关的路由界说在一个文件中,然后在app的路由界说中把一切路由兼并到一同。 todo.routes.ts 的内容如下:

// 省掉import
export const TodoRoutes: Route[] = [
  {
    path: 'todo',
    canActivateChild: [MyTodoGuard],
    children: [
      { path: 'list', component: TodoListComponent, resolve: { todos: MyTodoResolver } },
      { path: 'detail/:id', component: TodoDetailComponent, canDeactivate: [ CanLeaveTodoDetailGuard ] }
    ]
  }
];

然后在 app.routes.ts 中界说一个路由模块:

const routes: Routes = [
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: 'home', component: HomeComponent },
  ...TodoRoutes // 这儿便是将TodoRoutes列表里的内容兼并到routes
];
@NgModule({
 imports: [ RouterModule.forRoot(routes) ],
 exports: [ RouterModule ]
})
export classAppRoutingModule{ }

终究,在AppModule里边引进这个路由模块。

这种办法完成的路由无法完成子模块的延时加载,要完成延时加载,首要要将todo模块的路由修正成子路由模块,也便是要修正 todo.routes.ts :

// 省掉import
export const TodoRoutes: Route[] = [
  {
    path: 'todo',
    canActivateChild: [MyTodoGuard],
    children: [
      { path: 'list', component: TodoListComponent, resolve: { todos: MyTodoResolver } },
      { path: 'detail/:id', component: TodoDetailComponent, canDeactivate: [ CanLeaveTodoDetailGuard ] }
    ]
  }
];
// 经过下面的办法界说了一个子路由模块
@NgModule({
 imports: [ RouterModule.forChild(TodoRoutes) ],
 exports: [ RouterModule ]
})
export classTodoRoutingModule{ }

这儿,咱们界说了一个子路由模块, TodoRoutingModule ,它运用 RouterModule.forChild(TodoRoutes) 来创立。跟整个App的路由模块比较的话,主路由模块运用 RouterModule.forRoot(routes) 来界说。

界说好了子路由模块,咱们就在子模块里边引进它既可:

// 省掉import
@NgModule({
 imports: [CommonModule, FormsModule, TodoRoutingModule ],
 declarations: [TodoListComponent, TodoDetailComponent, TodoItemComponent],
 providers: [TodoService, MyTodoResolver, MyTodoGuard, CanLeaveTodoDetailGuard]
})
export classTodoModule{}

这样,咱们就界说好了一个子模块。当用户翻开 /todo/list 或 /todo/detail/* 时,这个子模块里边的相关页面就会展现,它也不会跟其他模块有任何交互。也便是说,进入和脱离这个子模块,都是经过路由跳转完成。这个子模块也是彻底独立的,可以独立开发,也可以很简略就用到其他运用里边。

延时加载子模块

下面,咱们就可以经过修正路由的装备,使得todo模块完成延时加载。Angular的路由模块现已供给了 loadChildren 界说可以直接帮咱们完成该功用。下面便是新的app路由界说

const routes: Routes = [
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: 'home', component: HomeComponent },
  { path: 'todo', loadChildren: 'app/todo/todo.module#TodoModule' },
  { path: 'lazy', loadChildren: 'app/lazy/lazy.module#LazyModule' }
];

@NgModule({
 imports: [ RouterModule.forRoot(routes) ],
 exports: [ RouterModule ]
})
export classAppRoutingModule{ }

在这儿,咱们关于 todo 途径,交给 app/todo/todo.module 里边的 TodoModule 模块处理。而在 TodoModule 模块里,现已有一个子路由的界说。

终究,再修正 app.module.ts ,确保它里边不再引进 TodoModule 。如此一来,咱们在主模块AppModule里边,没有引进 todo 模块的任何组件或服务。这样就能在彻底脱离 TodoModule 模块的状况下,运转主模块的功用。当用户翻开 /todo 里边的url时,就加载 app/lazy/lazy.module 里边的 LazyModule 模块,并交由它来处理呼应的url。

总结一下,完成延时加载子模块,首要是要留意下面几点:

子模块的路由用 RouterModule.forChild(TodoRoutes) 办法界说。 主模块不要引进子模块,也不要引进子模块的任何组件或服务,不然子模块就会被打包进主模块里。 只需子模块才会用到的Service在子模块的 providers 里边界说,假如是主模块和子模块都会用到的Service就用共用模块的办法界说。要留意这个Service的实例只能有一个。

运转

接下来咱们来看看运转的成果。(留意依据运转环境不同,文件巨细会不一样)

不启用延时加载

首要,咱们在 app.module.ts 引进 TodoModule ,这样 todo 模块不是延时加载的,只需 lazy 模块是延时加载的。咱们运用 ng serve 的办法运转测验服务器,并翻开页面,翻开几个页面今后,网络恳求如下:

检查图片

从图中可以看到,有一个3.4M的main的js文件,下面的 1.chunk.js 的 lazy 模块延时加载的。打包的文件的确是十分的大,由于lazy模块十分简略,仅仅显现了一个字符串在模板里。所以它的巨细也十分小,才5.8k。

延时加载形式

下面在把 TodoModule 模块从 app.module.ts 去掉,这样, todo 模块便是延时加载的,再看一下网络恳求:

检查图片

这下main文件变成了3.1M,lazy模块对应的js文件是 1.chunk.js ,仍是5.8k,todo模块对应的文件 0.chunk.js 是324K。可以看见一个很简略的todo模块,里边有service, rosolver, guards, 还有3个组件,里边别离都有模块、css,尽管文件不少,可是他们的完成实际上都很小。仅仅一个模块的文件,在未紧缩的状况下就有300多K,让我这个Angular2的忠诚粉丝都无语。

延时加载-prod形式

一般咱们在布置运用的时分,都会运用紧缩、混杂、兼并等办法来削减终究文件的巨细。运用angular-cli东西,除了在编译的时分供给打包的功用,乃至在测验的时分,也可以启用紧缩选项。咱们可以运转 ng serve -pro 来运用 prod 形式来发动测验服务器。在发动的进程中,可以看到许多相似下面的日志:

WARNING in 0.005fea95566fdabe23df.chunk.js from UglifyJs
Dropping unused function scheduleMicroTask [/Users/mavlarn/mydev/blog/angular2-tutorial/angular2-routes-lazy-module-webpack/~/@angular/forms/src/facade/lang.js:21,0]

可以看出,angular-cli的 prod 形式下编译的时分,去除了许多不需求的代码,这便是angular的 Tree Shaking 的功用。

运转今后,网络恳求如下:

检查图片

这下main文件削减到了221K,lazy模块对应的js文件是 1.chunk.js ,只需1.0k,todo模块对应的文件 0.chunk.js 是17.9K。一共巨细大概是240K左右,假如再运用GZip紧缩,应该可以到6,70K左右。在官方文档里说到,一个Angular2的简略实例,经过Tree Shaking、紧缩、GZip,终究下载的包巨细有50K。咱们这个实例究竟略微杂乱,完成了大多数的通用功用,如路由、guard、resolver、表单,也是用到了Rxjs里的 Observable ,所以终究紧缩后能有70K左右的话,也契合官方文档的说法。

编译后

终究,咱们再运用 ng build --prod 来看看用prod形式编译后的巨细:

检查图片

成果出乎意外,main文件的巨细比上面在prod形式下运转测验服务器大许多,到达800多K。应该是编译进程需求某些参数,或许是当时的angular-cli有什么bug。

再运用 ng build --prod --aot 编译,main文件的巨细是446K。尽管小了一点,可是也不契合预期。

总结

先说延时加载,应该都知道可以削减第一次加载的文件的巨细。特别是当某个模块运用了一些比较大第三方的js库,例如图形库等,那么,把这些模块独立出来,运用延时加载的办法,可以大大削减初次加载的时刻。关于Angular2的运用来说,假如咱们要界说 Component ,就从 @angular/core 里边引进 Component ,需求界说路由就从 @angular/router 里边引进`Router。所以,只需咱们规划好了整个App的模块、组件、路由,咱们就可以运用延时加载的功用使得主页文件尽或许的小。

运用模块化的开发,也能给咱们的开发和保护带来很大的便当,项目越大越大,模块化和组件化带来的便当就越显着。

现在Angular2的天坑

在网上,常常可以看到一些文章说Angular1或许2的一些坑。实际上,大部分都是由于运用不当,或许没有依照最佳实践去运用,特别是Angular1。尽管Angular1有本质上的功用问题,可是,经过杰出的全体规划、杰出的 代码标准和质量,仍是可以开宣布很流通的手机web运用。

可是,在预备这篇文章中的实例时,却遇到了几个严峻的问题,让我这个Angular2的忠诚粉丝也很无法。

Angular 2.2.2及以上版别的BUG

我在实例中运用的Angular的版别是2.2.1,假如用的版别是2.2.2 ~ 2.3.0之间,在运转或编译的时分,或许会呈现如下的过错:

ngCompiler.ReflectorHost is not a constructor
TypeError: ngCompiler.ReflectorHost is not a constructor

可以上Github检查该 issue 的状况。假如遇到这种问题,只能先运用2.2.1的版别。

Angular-Router

在这个实例中,延时加载的todo模块里边有一个service,咱们运用Angular的依靠注入的功用主动初始化以及比如这个服务的实例。可是,在3.1.2及以上的版别里边,这个服务会被创立屡次,每次激活相关路由的时分,就会创立一次。并且,只需在延时加载的形式才会发作这种过错。相关 issue

TypeScript

在我之前的教程里,判别用户是否具有某种权限,运用了如下的办法:

hasRole(role: string): boolean {
  return this.account && this.account.roles.includes(role);
}

可是,更新了TypeScript今后,该办法就不存在了,原因可以检查 这个 .

所以改成了用 indexOf(role) > 0 来判别列表里是否存在一个字符串。

尽管现在Angular还不是十分安稳,有一些Bug,乃至TypeScript也不安稳,可是,信任这些问题都可以很快处理。并且跟着结构越来越老练,也会越来越安稳。

并且,Angular2+Typescript的开发办法也十分便当,Typescript的强类型检查可以协助咱们削减编码的过错,进步功率。并且,咱们也可以很便利的检查结构的API,能省去许多查资料的时刻。

Angular2的许多思维十分适用于开发大型的运用。假如开发过大型的Java项目,就会发现学习Angular2是一件十分简略的工作。Angular2引进了许多面向目标的结构的思维,而这些,都是在面向目标范畴开发大型项目的多年开发经历。这些经历运用到前端开发,也能协助咱们更便利的开发和保护大型的前端项目。

尽管,Angular2的运用终究的打包文件十分大(咱们这个实例即便紧缩完后也有70K左右,可是假如用VUE的话会比这个小许多),可是跟着Angular2的越来越安稳,各种开发东西越来越老练,信任文件巨细的问题也可以有一个比较好的处理方案。由于Angular2的AOT、Tree Shaking的特性,为处理巨细的问题供给了条件。

以上便是本文的全部内容,期望对我们的学习有所协助,也期望我们多多支撑188bet注册网。

运用Vue.js+Node.js+MongoDB完成一个博客体系(附源码)
前语这篇文章完成的博客体系运用Vue做前端结构,Node+express做后端,数据库运用的是MongoDB。完成了用户注册、用户登录、博客办理(文章的修正和删去

Vue.js 2.0学习教程之从根底到组件详解
前语最近这段时刻里不断的做着Vue的技能共享,尽管不是什么深层次的代码底能架构,假如底层架构真说出来,我就不会做Vue.js2.0从根底到组件了,就

vue.js父组件运用外部目标的办法示例
最近在碰到有同学问我,vue父组件怎样运用外部目标,具体比如如下:有组件a:[email protected]="onClick"componenta/div//componeta...methods:{onClick(evt){//doSomething这儿只能

本周排行

更新排行

强悍的草根IT技能社区,这儿应该有您想要的! 友情链接:b2b电子商务
Copyright © 2010 touzhuwang75.com. All Rights Rreserved  京ICP备05050695号