资讯专栏INFORMATION COLUMN

从命令式到响应式(九)

Lin_R / 2434人阅读

摘要:让帮我们取消这个不用多说了,主要是采用,在模版本中让自已去取数据,再自动的取消。使用的操作符管理订阅思路是使用那些可以让流发出结束通知的操作符,将其添加到需要管理的流上,让自动取消订阅。

使用rxjs时什么时候取消订阅是我们必须要关心的,这个系列的前面几篇也提到过,原则是尽量不去手动订阅流,但手动订阅终究是无法避免的,今天主要总结下如何适时的取消订阅。

让angular帮我们取消

这个不用多说了,主要是采用 async pipe,在HTML模版本中让angular自已去取数据,再自动的取消。

在component中管理subscription

思路是,在component中订阅的流,在合适的生命周期中取消,最常见就是在OnDestroy的时候。两种方式,第一种组件维护一个subscription,其它的subscription通过add方法添加至这个subscription上,取消的时候调用这个subscription的unsubscribe方法,第二种,组件维护一个subscription数据,取消的时候遍历数组,调用每一个subscription的unsubscribe方法。

假设我们有一个服务,可以发送websocket的请求,处理请求的错误,同时还可以提供一些公共逻辑的处理,大概像下面这样:

// service.ts
@Injectable()
export class MyService {
    constructor(public websocket: WebsocketService) {}

    // 发送websocket请求
    request(paramObs: Observable): Subscription {
        return paramObs.subscribe(params => this.websocket.send(params));
    }

    // 处理响应的错误
    handleError(): Subscribe {
        return this.websocket.message.pipe(
            filter(res => res.flag === "request flag") // 取这个上面请求的结果
        ).subscribe(res => ...)
    }

    // 其它需要在服务中订阅后处理的逻辑
    otherLogic(params: Observable): Subscription {
        return params.subscribe(...) 
    }
}

第一种思路:

@Component({...})
export class MyComponent implement OnInit, OnDestroy {
    subscription: Subscription;

    constructor(private ser: MyService) { }

    ngOnInit() {
        this.subscription = this.ser.request(paramsObs1) // 参数是包含请求数据的流
            .add(this.otherLogic(paramsObs2)) // 参数是需要处理的数据流
            .add(this.ser.handleError())
    }

    ngOnDestroy() {
        this.subscription.unsubscribe();
    }
}

第二种思路:

@Component({...})
export class MyComponent implement OnInit, OnDestroy {
    subscriptions: Subscription[] = [];

    constructor(private ser: MyService) { }

    ngOnInit() {
        this.subscriptions = [
            this.ser.request(paramObs1), // 参数是包含请求数据的流
            this.ser.handleError(),
            this.otherLogic(paramsObs2) // 参数是需要处理的数据流
        ];
    }

    ngOnDestroy() {
        this.subscriptions.forEach(sub => sub.unsubscribe());
    }
}

除了写法上的不同外,最大的不同在于采用第一种写法时,你可能需要注意添加的顺序,假如例子中的paramsObs2参数流会出完成通知则会导致handleError也被取消掉,这种场景大家可以自己写个demo试下,第二种写法则不会,但可能重复去取消一些已经被取消过的流,好在这并不会导致错误的发生。

使用rxjs的操作符管理订阅

思路是使用那些可以让流发出结束通知的操作符,将其添加到需要管理的流上,让rxjs自动取消订阅。常用的有下面这些:

take操作符

此操作符会上当前流上取指定数量的值,然后发出完成通知,使用只想让otherLogic处理前3个数据,

ngOnInit() {
    this.ser.otherLogic(paramsObs2.take(3)); // 不再需要理会订阅产生的subscription了,处理3个值后自动取消订阅;
}

类似的操作符还有first,from,of等都会发出完成通知。

takeWhile操作符

此操作符添加到流上后,每一次发出值时都要检查操作符中传入的判定函数返回的结果是否为true,一旦返回false,输出流将会被取消掉,不再发出值,假设我们的paramsObs2的数据来自于一个formControl:

@Component({
    ...
    template: ``
})
export class MyComponent implement OnInit, OnDestroy {
    control = new FormControl("xxx");

    isAlive = true; // 添加一个变量控制流的结束

    ...

    ngOnInit() {
        ...
        this.ser.otherLogic(this.control.valueChanges.pipe(
            takeWhile(() => this.isAlive) // 传入了一个判定函数
        ))
    }

    ngOnDestroy() {
        this.isAlive = false; // 这里变为false;
    }
}
takeUntil操作符

此操作符和takeWhile不同,第一,接受的参数不是判定函数,而是Observable, 第二,传入的observable一旦发出值,输入流将会被取消订阅,不管发出的值是true还是fasle,或者是其它值。

@Component({
    ...
    template: ``
})
export class MyComponent implement OnInit, OnDestroy {
    control = new FormControl("xxx");

    constructor(
        ...
        private router: Router
    ){}

    ngOnInit() {
        ...
        this.ser.otherLogic(this.control.valueChanges.pipe(
            takeWhile(this.router.events) // 把router的事件流传了进去,只要router上有事件发出输出流就被取消
        ))
    }

    ...
}

这几种方法各有各有的特点,有的需要额外的变量但用起来简单粗爆,有的简洁明了但你需要花心思在其它条件上,在项目中可以根据实际情况选择最适合的使用。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97285.html

相关文章

  • 0开始用python写一个命令行小游戏(

    摘要:好了,今天终于到了你们期待已久的多行新僵尸。好,开始吧上篇链接从开始用写一个命令行小游戏八。多行游戏一开始我为了尽可能简化游戏,我用了一个单行数组,以模拟只有一行的游戏。一个形如的列表生成式等价于运行后的列表。 好了,今天终于到了你们期待已久的多行+新僵尸。其实我本来想把它们放在两个beta里解决的,但后来忘了,于是打包起来,跳过beta 5,直接发布了beta 6,就是今天的结束状态...

    WalkerXu 评论0 收藏0
  • 响应设计个人的一些总结

    摘要:所以一个网,甚至是响应式设计,在两个平台上都会损害您整体的。三响应式与如果把网站作为一个单独的网站,如果网站的内容与桌面版的内容相对缺少,导致用户回到桌面端的网站,会记录这种选择,使搜索排名降低,国内百度就不知道会怎样。 一、为什么需要响应式设计(responsible web design) 1. 响应式发展背景 1、屏幕尺寸的快速变化,iphone为320x480,分辨率在未来可以...

    LeoHsiun 评论0 收藏0
  • 2017-07-08 前端日报

    摘要:前端日报精选精读与提案知乎专栏第期认识引擎记录一次利用工具进行性能优化的真实案例简书中的使用规则教程继承的实现方法个人文章中文译组件渲染性能探索个人文章周刊第期表单性能的改进实践知乎专栏简单可重用的图表库知乎专栏 2017-07-08 前端日报 精选 精读 TC39 与 ECMAScript 提案 - 知乎专栏【第989期】认识 V8 引擎记录一次利用 Timeline/Perform...

    王岩威 评论0 收藏0
  • 命令响应(一)

    摘要:响应式命令式这两种编程风格的思维方式是完全相反的。第二种方式是工人主动去找工人索取生产手机所要的零件,然后生产一台完整的手机,这两种方式就对应的响应式和命令式。 angular2中内置了rxjs,虽然框架本身并没有强制开发者使用响应式风格来组织代码,但是从框架开发团队的角度可以看出他们必然是认同这种编程风格的。rxjs本质是基于函数式编程的响应式风格的库,函数式相对于面向对象来说更加抽...

    JayChen 评论0 收藏0
  • 利用angular4和nodejs-express构建一个简单的网站()—用户登录

    摘要:好了,废话少说,继续吧这一章主要讲利用控制用户登录。在前面的用户注册表单中使用了的响应式表单。在构造函数中声明了一个对象一个对象和对象对象。并在构造函数中用的方法更新了网页的标题。接下来导航到下一个页面,并提示用户登录成功。 最近工作比较忙,一直没有更新文章。原来看别人的文章感觉很过瘾,现在自己写才发现,要坚持下去真的很难。好了,废话少说,继续吧!这一章主要讲利用angularJs控制...

    Snailclimb 评论0 收藏0

发表评论

0条评论

Lin_R

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<