Comments (8)
A modular Observable would also be nice for frameworks (including Angular).
Perhaps a good approach to number 3 would be to leave it up to the developer to explicitly handle decoration (with a helper method on Observable
), and operators could be written as functions that expect to be called with context, which would fit nicely within the bind_operator ES proposal.
//map.js
export function map () {
// this == Observable instance
return new MapObservable(this);
}
//mymodule.js
import {Observable} from 'rx';
import {map} from './map';
//Plain old call
var observable = new Observable(...);
map.call(observable, (val) => val).subscribe(...);
//Decorate Observable
var MyObservable = Observable.decorateFrom(map);
(new MyObservable(...)).map(val => val).subscribe(...);
//Bind_operator style (I think)
(new Observable(...))::map(val => val).subscribe(...);
Whatever the solution to number 3, I think it's important for the "global" Rx object to be treated as immutable, and more explicitly decorated by the user. The best practice for app developers could be to create a module with the Rx object decorated with common operators for an application, which could be further decorated as needed by other parts of the application. Distributions like rx.lite and rx.all could also use this approach to have distributions with common operators, for users who aren't as byte-sensitive.
What do you think @trxcllnt? + @vsavkin
from rxjs.
My "Decorate Observable" proposal is flawed, since there are many Observable
subclasses. Decorating a copy of Observable
would require other implementations, like MapObservable
, to know about the decorated prototype they should be inheriting.
from rxjs.
@jeffbcross I've used the convention that the source Observable is the last argument to an operator, but the operator can default to this
, for example:
// src/operators/map.js
module.exports = function map(project, source) {
return new MapObservable(source || this, project);
};
However, this is in direct conflict with another feature I've been hoping to support: maintaining Observable
subtypes through the chain. If an operator returns a subclass of Observable
, subsequent operators should return the same subclass.
If we can ensure this, we won't need to save out the Observables
from operators that return subtypes, like multicast
, to interact with them later. It will also make subclassing and adding your own Observable
operators possible.
For operators, each Observable
subclass is essentially just a factory that proxies the operator arguments to the operator-specific Generator
subclass. If the Observable
constructor accepts source
, generatorFactory
, and generatorArguments
, the operator can delegate Generator
creation to the source Observable
's constructor:
// src/Observable.js
var Generator = require("rx/Generator");
function Observable(source, generatorFactory, generatorArguments) {
this.source = source;
this.generatorFactory = generatorFactory;
this.generatorArguments = generatorArguments || [];
}
Observable.prototype.constructor = Observable;
Observable.prototype.subscribe = function subscribe(_next, _throw, _return) {
if(_next && typeof _next === "object") {
return this._subscribe(_next);
}
return this._subscribe(new Generator(_next, _throw, _return);
};
Observable.prototype._subscribe = function _subscribe(generator) {
var generator2 = this.generatorFactory.apply(generator, this.generatorArguments);
var subscription = this.source.subscribe(generator2);
switch(typeof subscription) {
case "function":
return Generator.return(subscription);
case "object":
return subscription || Generator.empty();
default:
return Generator.empty();
}
}
// src/operators/map.js
var Generator = require("rx/Generator");
function MapGeneratorFactory(project) {
return new MapGenerator(this, project);
}
function MapGenerator(destination, project) {
this.project = project;
Generator.call(this, destination);
}
MapGenerator.prototype = Object.create(Generator.prototype);
MapGenerator.prototype._next = function _next(value) {
return this.destination.next(this.project(value));
}
module.exports = function map(project, source) {
return new (source || (source = this)).constructor(source, MapGeneratorFactory, [project]);
}
from rxjs.
I've used the convention that the source Observable is the last argument to an operator
I have (perhaps unfounded) concerns about adding too many optional arguments to our methods, and how that will affect the optimization of the library. It seems like in doing so we'll be creating a lot of polymorphic functions. That might be okay, if they all have monomorphic functions backing them, but that could end up bloating the library too.
Food for thought.
from rxjs.
I think we've got a good approach for this at the moment.
Right now we have each operator in it's own module, so if you're using a build system or a module system, you can reference those directly and get the desired effect. Also, I'm a big fan of the ES function bind proposal that @jeffbcross pointed out. It's already available in Babel, and hopefully the TypeScript people get on the ball with that. We don't need it, of course.
from rxjs.
@trxcllnt I'd be interested in knowing if you are still pursuing the idea of maintaining Observable subtypes through the chain or if it has been dropped. I dabbled with this idea using lodash's chaining mechanism but I don't think it was ready to be externalized.
from rxjs.
@calebboyd it has been dropped for now. There really isn't any prior art for maintaining a custom type through a fluent method chain. The ES7 function bind feature is more than enough to help most people's needs for chaining custom functions.
The major thing that killed this feature is that once native Observables land in-browser, ideally this whole library becomes a set of extension methods built on top of that. As people have learned with Promises, the in-browser Promise debugger only works with native Promises, and not Promises from libraries. Future tooling for Observable is likely to be the same.
This library is still pre-alpha though, so if consensus changes, we'll change it back.
from rxjs.
Thanks @Blesh for replying. I agree the ::
syntax is convenient. I almost wish there was something explicit like that for other language's extension methods (C#).
As for prior art, I'm not sure this pattern exists in JS, but Scala supports similar behavior with this.type
(mutable chains) and cough* Java, also has co-variant return types.
-- I'll keep watching, exited to see where this library is headed.
from rxjs.
Related Issues (20)
- '.now()' is not a function error is thrown when the value of DateTimestampProvider.delegate is not valid HOT 1
- TestScheduler expectObservable not respecting subscription marbles when using toEqual
- pipe expected 0 arguments HOT 5
- Incorrect @deprecated for fromEvent overloads HOT 2
- test issue
- test issue
- rxjs.dev very often inaccessible HOT 10
- export map means node always resolves CJS HOT 7
- RxJs ships generators instead of native async/await HOT 1
- bindCallback: resultSelector destructuring callback argument if it's array HOT 1
- `every` operator sending multiple values when re-entrant HOT 1
- [email protected] has peer deps?! Oops
- ObservableInput<T> should support Thennable<T>, not PromiseLike<T> HOT 1
- Delay, timer and possibly other operators have a maximum milliseconds value, even when date is passsed HOT 1
- lost stacktrace after promise is resolved HOT 1
- Teardown and error/complete messages are out of order HOT 2
- Issue with catchError HOT 1
- Synchronous emit to `switchMap` during the processing of previous emit prevents the first from unsubscribing HOT 4
- False positive in deprecation with mergMap HOT 1
- it's possible to return an array in catchError() HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rxjs.