Reactive-Extensions / RxJS

The Reactive Extensions for JavaScript
http://reactivex.io
Other
19.49k stars 2.1k forks source link

.forEach is confusingly documented #1336

Open jdetle opened 7 years ago

jdetle commented 7 years ago

Hi there, first off, I'd just like to say that I think the work you're doing is super cool and I'm having a blast learning functional reactive programming.

It took me some time to come to the conclusion that .forEach() and .subscribe() are the same function.

This link: http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-forEach, I get no indication that observable.subscribe() and observable.forEach() behave identically.

This link pushed me toward the conclusion: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/subscribe.md.

If I click on Language Specific information in : http://reactivex.io/documentation/operators/subscribe.html I get the verbatim answer that these operators are identical.

As a newbie trying to learn these things, I'd love to make a PR that:

  1. More readily displays the fact that forEach and subscribe are identical operators.
  2. Eliminates the confusion in the rxjs docs here

I'd love to hear thoughts from all you awesome RxJS maintainers.

jayphelps commented 7 years ago

I think you meant to post this on RxJS v5's issue tracker btw found here: https://github.com/ReactiveX/rxjs

In v5, forEach and subscribe are different. We need to document this better, but the code itself should be fairly straightforward to understand.

   * @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
   * @return {Promise} a promise that either resolves on observable completion or
   *  rejects with the handled error

So it accepts two params, first being a next handler/callback, the second being an optional constructor for Promise (this isn't likely necessary for a large majority of people).

It returns a Promise (using that constructor, or from global.Promise) that resolves on complete(), or rejects on error(). So you have the three states:

item$
  .forEach(value => console.log('next', value))
  .then(() => console.log('complete'), e => console.error('error', e));

// or using async/await proposed syntax

async function main() {
  try {
    await item$.forEach(value => console.log('next', value));
    console.log('complete');
  } catch (e) {
    console.error('error', e);
  }
}
lioobayoyo commented 6 years ago

In my Chrome 63.0 console, forEach on a Rx.Observable does not return a Promise, there is no .then method on the returned value. It seems it returns a Subscription.

Also the link to "the code itself" in previous answer is 404.

jayphelps commented 6 years ago

@lioobayoyo this is a pretty old thread 😄 in RxJS v4 (rx package on npm) forEach is just an alias for subscribe and returns a Disposable aka subscription. In RxJS v5 (rxjs package on npm) forEach is not the same as subscribe, instead it returns a Promise and has no way to access the underlying subscription.

Note that they are different npm packages. So it sounds like you're using RxJS v4, not v5. This repo is for v4 and v5 repo is here.