1、自己实现一个简单版的rxjs:SimpleObservable 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 SimpleObservable.ts class SimpleObservable { private observer: Array <Function >; constructor () { this .observer = []; } subscribe(_observer: Function ) { this .observer.push(_observer); let _index = this .observer.length - 1 ; let that = this ; return { _index: _index, unsubscribe: function ( ) { console .log("before:unsubscribe:" , that.observer); that.observer.splice(this ._index, 1 ); console .log("after :unsubscribe:" , that.observer); } }; } next(_data: any) { for (let i = 0 , len = this .observer.length; i < len; i++) { this .observer[i](_data); } } } export default SimpleObservable;
2、实现监听 场景:在项目中,不同页面的header样式一样,只有title文字不一样,比如page1显示的titile是’page1’,而page2显示的titile是’page2’,于是我把header做成了一个组件,而每个页面也是一个组件,因此通过SimpleObservable就可以实现组件与组件间的间接单向通信,即观察者(observer)监听被观察者(observable),被观察者触发观察者。
(备注:以下用ts语法,可以通过tsc编译生成对应js,再运行)
大致代码如下:
demo1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 demo1.ts import SimpleObservable from './SimpleObservable' ;let subscriptions=[];let headerTitleObservable = new SimpleObservable();let headerTitle_subscriptsion = headerTitleObservable .subscribe(_title => { console .log(`the header title is change to${_title } ` ); }); subscriptions.push(headerTitle_subscriptsion ); this .headerTitleObservable.next('page1' );subscriptions.forEach(subscription => { subscription.unsubscribe(); });
2、解除两个类的强耦合状态 使用观察订阅者模式,有时候能解除两个类的强耦合状态,比如,在我的项目中,我写了一个http拦截器httpInterceptor,用来过滤每一次http请求和响应,比如统一加access_token header,统一出错处理啊等等,我的httpInterceptor其中的一个功能,就是从服务器返回的响应头中检测登录状态是否已经失效或access_token是否已经过期,当检测到登录失效时,要在页面中弹出一个登录modal框(loginModalComponent),提醒用户重新登录。大致的代码如下:
(备注:以下采用ts语法,为了使理解起来更加容易,没有使用ts的依赖注入等特性)
未使用观察者模式:
demo2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 demo2.ts class LoginModalComponent { constructor () { } open() { console .log('##检测到access_token已经过期,打开login模态框##' ); console .log('请输入账号和密码,点击登录' ); } } class HttpInterceptor { loginModalComponent: LoginModalComponent = new LoginModalComponent();; constructor () { } handleHttpRes() { if (this .checkLoginInvalid) { this .loginModalComponent.open(); } } checkLoginInvalid() { return true ; } } let httpInterceptor = new HttpInterceptor();httpInterceptor.handleHttpRes();
以上示例代码是未使用观察者模式的情况下,需要在HttpInterceptor里new LoginModalComponent,从而导致HttpInterceptor和LoginModalComponent处于强耦合的状态,但是这样不符合HttpInterceptor拦截器的思想,因为HttpInterceptor拦截器是不应该和组件相关的东西进行耦合的,因此,采用观察者模式进行改进.
代码如下:
demo3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 demo3.ts class SimpleObservable { private observer: Array <Function >; constructor () { this .observer = []; } subscribe(_observer: Function ) { this .observer.push(_observer); let _index = this .observer.length - 1 ; let that = this ; return { _index: _index, unsubscribe: function ( ) { console .log("before:unsubscribe:" , that.observer); that.observer.splice(this ._index, 1 ); console .log("after :unsubscribe:" , that.observer); } }; } next(_data: any) { for (let i = 0 , len = this .observer.length; i < len; i++) { this .observer[i](_data); } } } class LoginModalComponent { constructor () { } open() { console .log('##检测到access_token已经过期,打开login模态框##' ); console .log('请输入账号和密码,点击登录' ); } } class HttpStatusService { login_invalid_observable = new SimpleObservable(); constructor () { } getLoginInvalidObservable() { return this .login_invalid_observable; } triggerLoginInvalidObservable() { this .login_invalid_observable.next('access_token is invalid.' ) } } let httpStatusService: HttpStatusService = new HttpStatusService();class HttpInterceptor { constructor () { } handleHttpRes() { if (this .checkLoginInvalid) { httpStatusService.triggerLoginInvalidObservable(); } } checkLoginInvalid() { return true ; } } class AppComponent { loginModalComponent: LoginModalComponent = new LoginModalComponent(); subscriptions: Array <any> = []; constructor () { this .init(); } init() { let subscription1 = httpStatusService.getLoginInvalidObservable().subscribe((err_msg ) => { this .loginModalComponent.open(); }); this .subscriptions.push(subscription1); } onDestroy() { this .subscriptions.forEach(subscription => { subscription.unsubscribe(); }); } } let appComponent = new AppComponent();let httpInterceptor = new HttpInterceptor();httpInterceptor.handleHttpRes(); appComponent.onDestroy();