Skip to content

Commit

Permalink
feat(forEach): add thisArg
Browse files Browse the repository at this point in the history
- adds thisArg as second argument to have symmetry with native Array forEach
- eliminates closures by leveraging named function instances
- adds test for thisArg passing
- updates tests to accommodate thisArg

BREAKING CHANGE: Observable.prototype.forEach argument order changed to accommodate thisArg. Optional PromiseCtor argument moved to third arg from second
closes #878
  • Loading branch information
benlesh committed Dec 8, 2015
1 parent d8f7297 commit 14ffce6
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 7 deletions.
16 changes: 14 additions & 2 deletions spec/observable-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('Observable', function () {
var expected = [1,2,3];
var result = Observable.of(1,2,3).forEach(function (x) {
expect(x).toBe(expected.shift());
}, Promise)
}, null, Promise)
.then(done);

expect(typeof result.then).toBe('function');
Expand All @@ -41,7 +41,7 @@ describe('Observable', function () {
}, function (err) {
expect(err).toBe('bad');
done();
}, Promise);
}, null, Promise);
});

it('should allow Promise to be globally configured', function (done) {
Expand All @@ -60,6 +60,18 @@ describe('Observable', function () {
done();
});
});

it('should accept a thisArg argument', function (done) {
var expected = [1,2,3];
var thisArg = {};
var result = Observable.of(1,2,3).forEach(function (x) {
expect(this).toBe(thisArg);
expect(x).toBe(expected.shift());
}, thisArg, Promise)
.then(done);

expect(typeof result.then).toBe('function');
});
});

describe('subscribe', function () {
Expand Down
29 changes: 24 additions & 5 deletions src/Observable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,12 @@ export class Observable<T> implements CoreOperators<T> {
/**
* @method forEach
* @param {Function} next a handler for each value emitted by the observable
* @param {PromiseConstructor} PromiseCtor? a constructor function used to instantiate the Promise
* @param {any} [thisArg] a `this` context for the `next` handler function
* @param {PromiseConstructor} [PromiseCtor] a constructor function used to instantiate the Promise
* @returns {Promise} a promise that either resolves on observable completion or
* rejects with the handled error
*/
forEach(next: (value: T) => void, PromiseCtor?: PromiseConstructor): Promise<void> {
forEach(next: (value: T) => void, thisArg: any, PromiseCtor?: PromiseConstructor): Promise<void> {
if (!PromiseCtor) {
if (root.Rx && root.Rx.config && root.Rx.config.Promise) {
PromiseCtor = root.Rx.config.Promise;
Expand All @@ -127,9 +128,27 @@ export class Observable<T> implements CoreOperators<T> {
throw new Error('no Promise impl found');
}

return new PromiseCtor<void>((resolve, reject) => {
this.subscribe(next, reject, resolve);
});
let nextHandler;

if (thisArg) {
nextHandler = function nextHandlerFn(value: any): void {
const { thisArg, next } = <any>nextHandlerFn;
return next.call(thisArg, value);
};
nextHandler.thisArg = thisArg;
nextHandler.next = next;
} else {
nextHandler = next;
}

const promiseCallback = function promiseCallbackFn(resolve, reject) {
const { source, nextHandler } = <any>promiseCallbackFn;
source.subscribe(nextHandler, reject, resolve);
};
(<any>promiseCallback).source = this;
(<any>promiseCallback).nextHandler = nextHandler;

return new PromiseCtor<void>(promiseCallback);
}

_subscribe(subscriber: Subscriber<any>): Subscription<T> | Function | void {
Expand Down

0 comments on commit 14ffce6

Please sign in to comment.