-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Modular Observable #29
Comments
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 //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. |
My "Decorate Observable" proposal is flawed, since there are many |
@jeffbcross I've used the convention that the source Observable is the last argument to an operator, but the operator can default to // 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 If we can ensure this, we won't need to save out the For operators, each // 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]);
} |
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. |
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. |
@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. |
Thanks @Blesh for replying. I agree the As for prior art, I'm not sure this pattern exists in JS, but Scala supports similar behavior with -- I'll keep watching, exited to see where this library is headed. |
Many in the node community have expressed interest in an extremely modular Observable implementation. Creating this issue to gather feedback on the idea of:
subscribe
function)require
'dThis way, the operators that rely on other operators (i.e.
concat
being amerge(1)
) canrequire
the modules they need, and the package manager can worry about factoring out common modules.@Blesh @jeffbcross
The text was updated successfully, but these errors were encountered: