使用Angular2建立一个可扩展单页应用

  本文主要讲解使用Angular2.JS、RxJSngrx等技术如何构建前端一个可伸缩扩展的单页应用。该应用基于后端RESTful API构建,当前用户之间可以通过P2P创建通讯连接,也能够和应用服务器实时通信,这里将出现多个通讯协议:HTTP, WebSocket, UDP via WebRTC。对应不同的数据包格式:

BERT 协议能够有效创建P2P通讯,实现二进制数据传输,入图片或任何使用文本方式传输不够效率的数据形式。RxJS是进行所有异步事件处理的总线,使用同样的通讯通道可以混合多个数据流格式,能够进行过滤filter,传输,处理等等。

模块设计

  由于该项目有多个可变数据源,用户操作是一个,来自后端的推送通知还有使用WebRTC用户之间的P2P通讯消息,为了有一个可预期的状态管理,需要统一这些可变的数据源与可变状态,有许多模式可以帮助我们实现这点,Redux是最流行的一种。下图是基于Redux对这个应用前端进行架构分层的组件图:

 

UI组件是用户直接操作的界面层,facade是UI的代表层,是一系列提供简化接口的对象,主要目标是允许我们能够触发应用的Action操作 ,从而调用Redux的reducer方法,将Action操作分发到异步服务层,因此类似dispatcher分发层。在facade层我们还会抽象我们的业务模型,假设我们我们开发一个Game,那么在GameComponent中我们使用GameModel抽象代表可变的状态。

技术选型

虽然React的react-router 支持懒加载,但是React生态系统还没有缺乏对象概念的依赖注入,而Angular 2的强项在于依赖注入和Webworker支持。

因此技术选型如下:

本应用开发的很多思想和理念都可以应用到其他框架比如React实现。

应用需求

作为我们演示应用,这个应用主要是一个小游戏,让你能够练习打字,给出一段文字,衡量你跟着打字打出来要用多长时间,可以几个用户一起比赛:

案例源码

 

模型定义

Gamemodel是代表可变的状态,代码如下:

@Injectable()

export class GameModel extends Model {

  games$: Observable<string>;

  game$: Observable<string>;

  constructor(protected _store: Store<any>,

              @Optional() @Inject(AsyncService) _services: AsyncService[]) {

    super(_services || []);

    this.games$ = this._store.select('games');

    this.game$ = this._store.select('game');

  }

  startGame() {

    this._store.dispatch(GameActions.startGame());

  }

  onProgress(text: string) {

    this.performAsyncAction(GameActions.gameProgress(text, new Date()))

      .subscribe(() => {

        // Do nothing, we're all good

      }, (data: any) => {

        if (data.invalidGame)

          this._store.dispatch(GameActions.invalidateGame());

      });

  }

  completeGame(time: number, text: string) {

    const action = GameActions.completeGame(time, text);

    this._store.dispatch(action);

    this.performAsyncAction(action)

      .subscribe(() => console.log('Done!'));

  }

}

 GameModel 能够被startGame action调用以开始一个游戏,, 能够被rameActions action 创建,比如:

this._store.dispatch(GameActions.startGame());

使用指定的Action调用dispatch方法会激活所有注册到存储中的reducer,通过使用传递的action作为一个参数会产生一个新的存储,存储将会通过game的被观察者发送到相应视图,下面结构:

 

原文:Scalable Single-Page Application Architecture

案例源码

Angular2的事件绑定和样式绑定

Reactive编程

Angular.js教程