From 526e4c92f0a2b1670aebf7cde39063657f47b684 Mon Sep 17 00:00:00 2001 From: ptaylor Date: Thu, 13 Aug 2015 20:25:17 -0700 Subject: [PATCH] feat(operator): add finally --- spec/operators/finally-spec.js | 47 ++++++++++++++++++++++++++++++++++ src/Observable.ts | 3 +++ src/Rx.ts | 5 ++++ src/operators/finally.ts | 35 +++++++++++++++++++++++++ 4 files changed, 90 insertions(+) create mode 100644 spec/operators/finally-spec.js create mode 100644 src/operators/finally.ts diff --git a/spec/operators/finally-spec.js b/spec/operators/finally-spec.js new file mode 100644 index 0000000000..e20ba2ee7b --- /dev/null +++ b/spec/operators/finally-spec.js @@ -0,0 +1,47 @@ +/* globals describe, it, expect */ +var Rx = require('../../dist/cjs/Rx'); +var Observable = Rx.Observable; + +describe('Observable.prototype.finally()', function () { + it('should call finally after complete', function (done) { + var completed = false; + Observable.of(1, 2, 3) + .finally(function(x) { + expect(completed).toBe(true); + done(); + }) + .subscribe(null, null, function() { + completed = true; + }); + }); + + it('should call finally after error', function (done) { + var thrown = false; + Observable.of(1, 2, 3) + .map(function(x) { + if(x === 3) { + throw x; + } + return x; + }) + .finally(function(x) { + expect(thrown).toBe(true); + done(); + }) + .subscribe(null, function() { + thrown = true; + }); + }); + + it('should call finally upon disposal', function (done) { + var disposed = false; + var subscription = Observable + .timer(100) + .finally(function(x) { + expect(disposed).toBe(true); + done(); + }).subscribe(); + disposed = true; + subscription.unsubscribe(); + }); +}); \ No newline at end of file diff --git a/src/Observable.ts b/src/Observable.ts index 56695898fa..2a70c5d6f2 100644 --- a/src/Observable.ts +++ b/src/Observable.ts @@ -149,4 +149,7 @@ export default class Observable { catch: (selector: (err: any, source: Observable, caught: Observable) => Observable) => Observable; retryWhen: (notifier: (errors: Observable) => Observable) => Observable; + + ensure: (ensure: () => void, thisArg?: any) => Observable; + finally: (ensure: () => void, thisArg?: any) => Observable; } diff --git a/src/Rx.ts b/src/Rx.ts index 18b4e55a8c..85a3a6b5ef 100644 --- a/src/Rx.ts +++ b/src/Rx.ts @@ -143,6 +143,11 @@ import retryWhen from './operators/retryWhen'; observableProto.catch = _catch; observableProto.retryWhen = retryWhen; +import _finally from './operators/finally'; + +observableProto.ensure = _finally; +observableProto.finally = _finally; + export default { Subject, Scheduler, diff --git a/src/operators/finally.ts b/src/operators/finally.ts new file mode 100644 index 0000000000..b1ab544d95 --- /dev/null +++ b/src/operators/finally.ts @@ -0,0 +1,35 @@ +import Operator from '../Operator'; +import Observer from '../Observer'; +import Subscriber from '../Subscriber'; +import Subscription from '../Subscription'; + +import tryCatch from '../util/tryCatch'; +import {errorObject} from '../util/errorObject'; +import bindCallback from '../util/bindCallback'; + +export default function _finally(finallySelector: () => void, thisArg?: any) { + return this.lift(new FinallyOperator(thisArg ? + <() => void> bindCallback(finallySelector, thisArg, 2) : + finallySelector)); +} + +export class FinallyOperator extends Operator { + + finallySelector: () => void; + + constructor(finallySelector: () => void) { + super(); + this.finallySelector = finallySelector; + } + + call(observer: Observer): Observer { + return new FinallySubscriber(observer, this.finallySelector); + } +} + +export class FinallySubscriber extends Subscriber { + constructor(destination: Observer, finallySelector: () => void) { + super(destination); + this.add(new Subscription(finallySelector)); + } +}