use highland stream for deferred calcuation - highland.js

I am trying to use a highland stream to pass back two objects: another data stream and a metadata object. I create the stream:
const outputStream = ...;
const hstream = _.([outputStream]);
client.connect( .. function() {
// fill data stream & also compute metadata, then
hstream.append(meta);
hstream.append(_.nil);
});
Later I consume this using:
hstream.apply(function(dataStream, meta) {
...
});
The problem is that the function called by apply acts before hstream has come to an end, and doesn't see the "meta" object. How can I reconfigure this so that apply is not called until hstream has both objects in it?

The following works:
const outputStream = ...;
const hstream = _.();
client.connect( .. function() {
// fill data stream & also compute metadata, then:
...
hstream.write(outputStream);
hstream.write(meta);
hstream.end();
});
In general I find highland streams to be quite powerful and flexible, but the abstraction is not very clear. In the current case there is nothing explicit
in the interface that makes it clear that the first version I wrote considers itself "finished" even though you can call append synchronously. Perhaps more doc and/or explicit options... e.g in the current case:
const hstream = _.([outputStream], {lazy: true})
(Or something like this...)

Related

Subject-like RxJS Observable that transparently pipes through flatMap

When using Dependency injection in Angular I often need to subscribe to an observable that I haven't yet created!
I often end up using something like this:
// create behavior subject OF Observable<number>
const subject = new BehaviorSubject<Observable<number>>(EMPTY);
// subscribe to it, using flatMap such as to 'unwrap' the observable stream
const unwrappedSubject = subject.pipe(flatMap((x: number) => x));
unwrappedSubject.subscribe(s => console.log(s));
// now actually create the observable stream
const tim = timer(1000, 1000);
// set it into the subject
subject.next(tim);
This uses flatMap to 'unwrap' the observable contained in the subject.
This works fine, but frankly it always feels 'icky'.
What I really want is something like this, where the consumer of the subject treats the instance of the Subject as Observable<number> without having to pipe it every usage.
const subject = new UnwrappingBehaviorSubject<number>(EMPTY);
subject.subscribe((x: number) => console.log(x));
// this could use 'next', but that doesn't feel quite right
subject.setSource(timer(1000, 1000));
I'm aware that I could subscribe to the timer and hook it up directly to the subject, but I also want to avoid an explicit subscribe call because that complicates the responsibility of unsubscribing.
timer(1000, 1000).subscribe(subject);
Is there a nice way to achieve this?
The Subject.ts and BehaviorSubject.ts source files get more complicated than I expected. I'm scared I'll end up with horrible memory leaks if I try to fork it.
I think this would be another way to solve it:
foo.component.ts
export class FooComponent {
private futureObservable$ = new Observable(subscriber => {
// 'Saving' the subscriber for when the observable is ready.
this.futureObservableSubscriber = subscriber;
// The returned function will be invoked when the below mentioned subject instance
// won't have any subscribers(after it had at least one).
return () => this.futureObservableSubscription.unsubscribe();
}).pipe(
// You can mimic the Subject behavior from your initial solution with the
// help of the `share` operator. What it essentially does it to *place*
// a Subject instance here and if multiple subscriptions occur, this Subject instance
// will keep track of all of them.
// Also, when the first subscriber is registered, the observable source(the Observable constructor's callback)
// will be invoked.
share()
);
private futureObservableSubscriber = null;
// We're using a subscription so that it's easier to collect subscriptions to this observable.
// It's also easier to unsubscribe from all of them at once.
private futureObservableSubscription = new Subscription();
constructor (/* ... */) {};
ngOnInit () {
// If you're using `share`, you're safe to have multiple subscribers.
// Otherwise, the Observable's callback(i.e `subscriber => {...}`) will be called multiple times.
futureObservable$.subscribe(/* ... */);
futureObservable$.subscribe(/* ... */);
}
whenObservableReady () {
const tim = timer(1000, 1000);
// Here we're adding the subscription so that is unsubscribed when the main observable
// is unsubscribed. This part can be found in the returned function from the Observable's callback.
this.futureObservableSubscription.add(tim.subscribe(this.futureObservableSubscriber));
}
};
Indeed, a possible downside is that you'll have to explicitly subscribe, e.g in the whenObservableReady method.
With this approach you can also have different sources:
whenAnotherObservableReady () {
// If you omit this, it should mean that you will have multiple sources at the same time.
this.cleanUpCrtSubscription();
const tim2 = timer(5000, 5000);
this.futureObservableSubscription.add(tim2.subscribe(this.futureObservableSubscriber));
}
private cleanUpCrtSubscription () {
// Removing the subscription created from the current observable(`tim`).
this.futureObservableSubscription.unsubscribe();
this.futureObservableSubscription = new Subscription();
}

BehaviorSubject send the same state reference to all subscribers

In our Single Page Application we've developed a centralized store class that uses an RxJS behavior subject to handle the state of our application and all its mutation. Several components in our application are subscribing to our store's behavior subject in order to receive any update to current application state. This state is then bound to UI so that whenever state changes, UI reflect those changes. Whenever a component wants to change a part of the state, we call a function exposed by our store that does the required work and updates the state calling next on the behavior subject. So far nothing special. (We're using Aurelia as a framework which performs 2 way binding)
The issue we are facing is that as soon as a component changes it's local state variable it receives from the store, other components gets updated even if next() wasn't called on the subejct itself.
We also tried to subscribe on an observable version of the subject since observable are supposed to send a different copy of the data to all subscriber but looks like it's not the case.
Looks like all subject subscriber are receiving a reference of the object stored in the behavior subject.
import { BehaviorSubject, of } from 'rxjs';
const initialState = {
data: {
id: 1,
description: 'initial'
}
}
const subject = new BehaviorSubject(initialState);
const observable = subject.asObservable();
let stateFromSubject; //Result after subscription to subject
let stateFromObservable; //Result after subscription to observable
subject.subscribe((val) => {
console.log(`**Received ${val.data.id} from subject`);
stateFromSubject = val;
});
observable.subscribe((val) => {
console.log(`**Received ${val.data.id} from observable`);
stateFromObservable = val;
});
stateFromSubject.data.id = 2;
// Both stateFromObservable and subject.getValue() now have a id of 2.
// next() wasn't called on the subject but its state got changed anyway
stateFromObservable.data.id = 3;
// Since observable aren't bi-directional I thought this would be a possible solution but same applies and all variable now shows 3
I've made a stackblitz with the code above.
https://stackblitz.com/edit/rxjs-bhkd5n
The only workaround we have so far is to clone the sate in some of our subscriber where we support edition through binding like follow:
observable.subscribe((val) => {
stateFromObservable = JSON.parse(JSON.stringify(val));
});
But this feels more like a hack than a real solution. There must be a better way...
Yes, all subscribers receive the same instance of the object in the behavior subject, that is how behavior subjects work. If you are going to mutate the objects you need to clone them.
I use this function to clone my objects I am going to bind to Angular forms
const clone = obj =>
Array.isArray(obj)
? obj.map(item => clone(item))
: obj instanceof Date
? new Date(obj.getTime())
: obj && typeof obj === 'object'
? Object.getOwnPropertyNames(obj).reduce((o, prop) => {
o[prop] = clone(obj[prop]);
return o;
}, {})
: obj;
So if you have an observable data$ you can create an observable clone$ where subscribers to that observable get a clone that can be mutated without affecting other components.
clone$ = data$.pipe(map(data => clone(data)));
So components that are just displaying data can subscribe to data$ for efficiency and ones that will mutate the data can subscribe to clone$.
Have a read on my library for Angular https://github.com/adriandavidbrand/ngx-rxcache and my article on it https://medium.com/#adrianbrand/angular-state-management-with-rxcache-468a865fc3fb it goes into the need to clone objects so we don't mutate data we bind to forms.
It sounds like the goals of your store are the same as my Angular state management library. It might give you some ideas.
I am not familar with Aurelia or if it has pipes but that clone function is available in the store with exposing my data with a clone$ observable and in the templates with a clone pipe that can be used like
data$ | clone as data
The important part is knowing when to clone and not to clone. You only need to clone if the data is going to be mutated. It would be really inefficient to clone an array of data that is only going to be displayed in a grid.
The only workaround we have so far is to clone the state in some of our subscriber where we support edition through binding like follow:
I don't think I can answer that without rewriting your store.
const initialState = {
data: {
id: 1,
description: 'initial'
}
}
That state object has deeply structured data. Everytime you need to mutate the state the object needs to be reconstructed.
Alternatively,
const initialState = {
1: {id: 1, description: 'initial'},
2: {id: 2, description: 'initial'},
3: {id: 3, description: 'initial'},
_index: [1, 2, 3]
};
That is about as deep of a state object that I would create. Use a key/value pair to map between IDs and the object values. You can now write selectors easily.
function getById(id: number): Observable<any> {
return subject.pipe(
map(state => state[id]),
distinctUntilChanged()
);
}
function getIds(): Observable<number[]> {
return subject.pipe(
map(state => state._index),
distinctUntilChanged()
);
}
When you want change a data object. You have to reconstruct the state and also set the data.
function append(data: Object) {
const state = subject.value;
subject.next({...state, [data.id]: Object.freeze(data), _index: [...state._index, data.id]});
}
function remove(id: number) {
const state = {...subject.value};
delete state[id];
subject.next({...state, _index: state._index.filter(x => x !== id)});
}
Once you have that done. You should freeze downstream consumers of your state object.
const subject = new BehaviorSubject(initialState);
function getStore(): Observable<any> {
return subject.pipe(
map(obj => Object.freeze(obj))
);
}
function getById(id: number): Observable<any> {
return getStore().pipe(
map(state => state[id]),
distinctUntilChanged()
);
}
function getIds(): Observable<number[]> {
return getStore().pipe(
map(state => state._index),
distinctUntilChanged()
);
}
Later when you do something like this:
stateFromSubject.data.id = 2;
You'll get a run-time error.
FYI: The above is written in TypeScript
The big logical issue with your example is that the object forwarded by the subject is actually a single object reference. RxJS doesn't do anything out of the box to create clones for you, and that is fine otherwise it would result in unnecessary operations by default if they aren't needed.
So while you can clone the value received by the subscribers, you're still not save for access of BehaviorSubject.getValue(), which would return the original reference. Besides that having same refs for parts of your state is actually beneficial in lots of ways as e.g arrays can be re-used for multiple displaying components vs having to rebuild them from scratch.
What you want to do instead is to leverage a single-source-of-truth pattern, similar to Redux, where instead of making sure that subscribers get clones, you're treating your state as immutable object. That means every modification results in a new state. That further means you should restrict modifications to actions, (actions + reducers in Redux) which construct a new state of the current plus the necessary changes and return the new copy.
Now all of that might sound like a lot of work but you should take a look at the official Aurelia Store Plugin, which is sharing pretty much the same concept as you have plus making sure that best ideas of Redux are brought over to the world of Aurelia.

Return a Javascript Promise value AKA Keras.js prediction

I'm new to Javascript and getting a bit bogged down with Promises in regards to predictions in Keras.JS
Basically i need to get the prediction value out of a promise (Keras Model) so I can pass it to another function. The following code is taken from the Keras.js github.
var predictions = function () {
model
.ready()
.then(() => {
// input data object keyed by names of the input layers
// or `input` for Sequential models
// values are the flattened Float32Array data
// (input tensor shapes are specified in the model config)
console.log('Model ready',x_pred )
var inputData = {
"input": new Float32Array(x_pred)
};
console.log('input data ready')
// make predictions
return model.predict(inputData)
})
.then(outputData => {
// outputData is an object keyed by names of the output layers
// or `output` for Sequential models
// e.g.,
// outputData['fc1000']
//console.log("outputData", outputData)
const output = new Float32Array(outputData.output)
console.log( output )
})
};
Now, the console reads the contents of my prediction - so the model is doing what I want it to do. But I need to take that prediction and pass it to another function. The following just points to my model promise and the output is undefined.
console.log(outpreds, output)
I understand that this is how the promise is meant to work but once the promise has been fulfilled I would really like to be able to do further things with output. unfortunately as I am using Electron/NodeJS I can't access async/await
Can anyone point me in the right direction?

redux-observable: Mapping to an action as soon as another was triggered at least once

I have an SPA that is loading some global/shared data (let's call this APP_LOAD_OK) and page-specific data (DASHBOARD_LOAD_OK) from the server. I want to show a loading animation until both APP_LOAD_OK and DASHBOARD_LOAD_OK are dispatched.
Now I have a problem with expressing this in RxJS. What I need is to trigger an action after each DASHBOARD_LOAD_OK, as long as there had been at least one APP_LOAD_OK. Something like this:
action$
.ofType(DASHBOARD_LOAD_OK)
.waitUntil(action$.ofType(APP_LOAD_OK).first())
.mapTo(...)
Does anybody know, how I can express it in valid RxJS?
You can use withLatestFrom since it will wait until both sources emit at least once before emitting. If you use the DASHBOARD_LOAD_OK as the primary source:
action$.ofType(DASHBOARD_LOAD_OK)
.withLatestFrom(action$.ofType(APP_LOAD_OK) /*Optionally*/.take(1))
.mapTo(/*...*/);
This allows you to keep emitting in the case that DASHBOARD_LOAD_OK fires more than once.
I wanted to avoid implementing a new operator, because I thought my RxJS knowledge was not good enough for that, but it turned out to be easier than I thought. I am keeping this open in case somebody has a nicer solution. Below you can find the code.
Observable.prototype.waitUntil = function(trigger) {
const source = this;
let buffer = [];
let completed = false;
return Observable.create(observer => {
trigger.subscribe(
undefined,
undefined,
() => {
buffer.forEach(data => observer.next(data));
buffer = undefined;
completed = true;
});
source.subscribe(
data => {
if (completed) {
observer.next(data);
} else {
buffer.push(data);
}
},
observer.error.bind(observer),
observer.complete.bind(observer)
);
});
};
If you want to receive every DASHBOARD_LOAD_OK after the first APP_LOAD_OK You can simply use skipUntil:
action$ .ofType(DASHBOARD_LOAD_OK)
.skipUntil(action$.ofType(APP_LOAD_OK).Take(1))
.mapTo(...)
This would only start emitting DASHBOARD_LOAD_OK actions after the first APP_LOAD_OK, all actions before are ignored.

When to use asObservable() in rxjs?

I am wondering what is the use of asObservable:
As per docs:
An observable sequence that hides the identity of the
source sequence.
But why would you need to hide the sequence?
When to use Subject.prototype.asObservable()
The purpose of this is to prevent leaking the "observer side" of the Subject out of an API. Basically to prevent a leaky abstraction when you don't want people to be able to "next" into the resulting observable.
Example
(NOTE: This really isn't how you should make a data source like this into an Observable, instead you should use the new Observable constructor, See below).
const myAPI = {
getData: () => {
const subject = new Subject();
const source = new SomeWeirdDataSource();
source.onMessage = (data) => subject.next({ type: 'message', data });
source.onOtherMessage = (data) => subject.next({ type: 'othermessage', data });
return subject.asObservable();
}
};
Now when someone gets the observable result from myAPI.getData() they can't next values in to the result:
const result = myAPI.getData();
result.next('LOL hax!'); // throws an error because `next` doesn't exist
You should usually be using new Observable(), though
In the example above, we're probably creating something we didn't mean to. For one, getData() isn't lazy like most observables, it's going to create the underlying data source SomeWeirdDataSource (and presumably some side effects) immediately. This also means if you retry or repeat the resulting observable, it's not going to work like you think it will.
It's better to encapsulate the creation of your data source within your observable like so:
const myAPI = {
getData: () => return new Observable(subscriber => {
const source = new SomeWeirdDataSource();
source.onMessage = (data) => subscriber.next({ type: 'message', data });
source.onOtherMessage = (data) => subscriber.next({ type: 'othermessage', data });
return () => {
// Even better, now we can tear down the data source for cancellation!
source.destroy();
};
});
}
With the code above, any behavior, including making it "not lazy" can be composed on top of the observable using RxJS's existing operators.
A Subject can act both as an observer and an observable.
An Obervable has 2 methods.
subscribe
unsubscribe
Whenever you subscribe to an observable, you get an observer which has next, error and complete methods on it.
You'd need to hide the sequence because you don't want the stream source to be publicly available in every component. You can refer to #BenLesh's example, for the same.
P.S. : When I first-time came through Reactive Javascript, I was not able to understand asObservable. Because I had to make sure I understand the basics clearly and then go for asObservable. :)
In addition to this answer I would mention that in my opinion it depends on the language in use.
For untyped (or weakly typed) languages like JavaScript it might make sense to conceal the source object from the caller by creating a delegate object like asObservable() method does. Although if you think about it it won't prevent a caller from doing observable.source.next(...). So this technique doesn't prevent the Subject API from leaking, but it indeed makes it more hidden form the caller.
On the other hand, for strongly typed languages like TypeScript the method asObservable() doesn't seem to make much sense (if any).
Statically typed languages solve the API leakage problem by simply utilizing the type system (e.g. interfaces). For example, if your getData() method is defined as returning Observable<T> then you can safely return the original Subject, and the caller will get a compilation error if attempting to call getData().next() on it.
Think about this modified example:
let myAPI: { getData: () => Observable<any> }
myAPI = {
getData: () => {
const subject = new Subject()
// ... stuff ...
return subject
}
}
myAPI.getData().next() // <--- error TS2339: Property 'next' does not exist on type 'Observable<any>'
Of course, since it all compiles to JavaScript in the end of the day there might still be cases when you want to create a delegate. But my point is that the room for those cases is much smaller then when using vanilla JavaScript , and probably in majority of cases you don't need that method.
(Typescript Only) Use Types Instead of asObservable()
I like what Alex Vayda is saying about using types instead, so I'm going to add some additional information to clarify.
If you use asObservable(), then you are running the following code.
/**
* Creates a new Observable with this Subject as the source. You can do this
* to create customize Observer-side logic of the Subject and conceal it from
* code that uses the Observable.
* #return {Observable} Observable that the Subject casts to
*/
asObservable(): Observable<T> {
const observable = new Observable<T>();
(<any>observable).source = this;
return observable;
}
This is useful for Javascript, but not needed in Typescript. I'll explain why below.
Example
export class ExampleViewModel {
// I don't want the outside codeworld to be able to set this INPUT
// so I'm going to make it private. This means it's scoped to this class
// and only this class can set it.
private _exampleData = new BehaviorSubject<ExampleData>(null);
// I do however want the outside codeworld to be able to listen to
// this data source as an OUTPUT. Therefore, I make it public so that
// any code that has reference to this class can listen to this data
// source, but can't write to it because of a type cast.
// So I write this
public exampleData$ = this._exampleData as Observable<ExampleData>;
// and not this
// public exampleData$ = this._exampleData.asObservable();
}
Both do the samething, but one doesn't add additional code calls or memory allocation to your program.
❌this._exampleData.asObservable();❌
Requires additional memory allocation and computation at runtime.
✅this._exampleData as Observable<ExampleData>;✅
Handled by the type system and will NOT add additional code or memory allocation at runtime.
Conclusion
If your colleagues try this, referenceToExampleViewModel.exampleData$.next(new ExampleData());, then it will be caught at compile time and the type system won't let them, because exampleData$ has been casted to Observable<ExampleData> and is no longer of type BehaviorSubject<ExampleData>, but they will be able to listen (.subscribe()) to that source of data or extend it (.pipe()).
This is useful when you only want a particular service or class to be setting the source of information. It also helps with separating the input from the output, which makes debugging easier.

Resources