Creating an observable using sendSync is easy. I'd like to create an of observable using ipcMain.on without using a simple callback.
return of(this.electronService.ipcRenderer.sendSync(channel.IPCMAIN_REQUEST_DATA));
Something similar, but not working.
return this.electronService.ipcRenderer.on(channel.IPCMAIN_RESPONSE_DATA, (event , response) => {
return of(response);
});
Try with this
return (new Observable(subscriber=>{
this.electronService.ipcRenderer.on(channel.IPCMAIN_RESPONSE_DATA, (event , response) => {
subscriber.next(response)
});
}));
If the event is fired then the observable will emit a new value
Try constructing the Observable like this (rxjs 5):
return Observable.fromEvent(ipcRenderer, channelName, (event, payload) => payload);
It should remove the listener when you unsubscribe the Observable.
Related
From this documentation:
RxJS introduces Observables, a new Push system for JavaScript. An Observable is a Producer of multiple values, "pushing" them to Observers (Consumers).
Subscribing to an Observable is analogous to calling a Function.
To invoke an Observable we should call the subscribe() function from the Observable object itself and pass the observer as the consumer of the data delivered by the observable like:
observable.subscribe( { /*this is an observer*/ } );
Also this documentation says:
What is an Observer? An Observer is a consumer of values delivered by an Observable. Observers are simply a set of callbacks, one for each type of notification delivered by the Observable: next, error, and complete. The following is an example of a typical Observer object:
On the other hand the first documentation says:
The Observable constructor takes one argument: the subscribe function.
The following example creates an Observable to emit the string 'hi' every second to a subscriber.
import { Observable } from 'rxjs';
const observable = new Observable(function subscribe(subscriber) {
const id = setInterval(() => {
subscriber.next('hi')
}, 1000);
});
When calling observable.subscribe with an Observer, the function subscribe in new Observable(function subscribe(subscriber) {...}) is run for that given subscriber. Each call to observable.subscribe triggers its own independent setup for that given subscriber.
So the entity Subscriber is just the argument passed into the subscribe function when creating a new Observable? If not who is the subscriber?
Are Observers and Subscribers the same entity? as mentioned in this documentation
Why isn't the code that invokes observable.subscribe({observer as call backs}) the subscriber of the observable? Like the consumer of a function's return value is the code that makes the function call.
COMPLETE DESIGN PATTERN EXPLANATION
Observer
const observer = {
next: v => /* code for next callback*/,
error: err => /* code for error callback*/,
complete: () => /* code for completion callback*/
}
Subscription
const subscription = {
unsubscribe: () => /* code for unsubscribe callback */
}
Observable
const observable1 = from([1,2,3,4,5]);
const observable2 = of(1,2,3,4,5);
const observable3 = new Observable(observer => {
observer.next(1);
observer.next(2);
observer.next(3);
observer.next(4);
observer.next(5);
observer.complete();
return { // return a subscription
unsubscribe: () => /* code for unsubscribe callback */
};
});
Subscribe and use the Returned Subscription
// Store a subscription
const subscription = observable3.subscribe(observer);
// Invoke the unsubscribe callback defined by the observable.
subscription.unsubscribe();
Okay. Then What is a Subscriber?
[Subscriber] Implements the Observer interface and extends the Subscription class. While the Observer is the public API for consuming the values of an Observable, all Observers get converted to a Subscriber... Subscriber is a common type in RxJS, and crucial for implementing operators, but it is rarely used as a public API.
Are observers and subscribers the same thing? Kind of, yes? Depends on how concretely you ask the question.
Consider this:
observable3.subscribe({
next: v => /* code for next callback */
});
obsevable3.subscribe(
v => /* code for next callback */
);
The first is an object with only one observer property defined. The second is simply a lambda function. They both end up generating basically the same subscriber.
I am new to rxjs and not sure how to implement the follow logic. Any suggestion will be appreciated.
Background
I am going to implement the communication between host website and an iframe in it with postMessage. Since postMessage is one-way only, I would like to implement the logic to wait for 'response' by myself when a message is sent from host website to iframe.
I have a sync function called send(message) to invoke the postMessage to send message to iframe. Then I would like to have another function with the follow logic.
public async sendAndWait(message): Promise<responseObj> {
// 1. create an observable to wait to message event with timeout
// my first thought is as follow but I feel like it does not work
// fromEvent(window, 'message')
// .pipe(timeout(timeoutInMs))
// .subscribe(event => {
// console.info(event);
// });
// 2. run `send(message)` function
// 3. do not finish this function until timeout or receive event in the previous subscription.
}
When I use the function, I would like to have
let response = await sendAndWait(message);
Not sure if it is possible to implement? Thank you
You cannot stop code execution in JS (using Async-Await, a Promise object is returned behind the scenes. so that the code is never waiting)
Consider implementing it in the following way:
let response: responseObj;
function main(): void {
sendAndWait(MESSAGE_OBJECT).subscribe(x => response = x)
}
function sendAndWait(message): Observable<responseObj> {
send(message)
return fromEvent(window, 'message')
.pipe(
timeout(timeoutInMs),
first()
)
}
Or optionally returning Promise:
async function sendAndWait(message): Promise<void> {
send(message)
const response = await fromEvent(window, 'message')
.pipe(
timeout(timeoutInMs),
first(),
toPromise()
)
}
I have an app that uses ngrx
Once a client updates a product, it uses a websocket to update all clients.
This works, by subscribing to the socket, so after a next method is called on the socket, it calls an action that handles the side effects of updating
But, now when it comes to deleting and adding, I'd like to use the same socket effect but change its final action call
Or if someone can suggest a better way
Socket service:
export class SocketService {
socket$ = Observable.webSocket( 'ws://localhost:1234');
}
effects:
//This is called from component to start the update process
#Effect({dispatch:false}) beginUpdate$: Observable<any> = this.actions$
.ofType<fromBlogActions.BlogUpdateStartAction>(fromBlogActions.BLOG_UPDATE_START_ACTION)
.map((action:any)=>{
console.log(action)
return action.payload;
})
.do((action)=> this.socketService.socket$.next(JSON.stringify(action)))
//Calls the next method to send data to the websocket
//The below watches for data emitted from the websocket
//Then calls the BlogUpdatedAction, what I need is for it to call a different action based on action type
#Effect() watchSocket$ = this.socketService.socket$
.map((action:BlogPayLoad)=>{
console.log(action)
return action
})
.mergeMap((action)=> [new fromBlogActions.BlogUpdatedAction(action)])
It should be possible like this:
#Effect() watchSocket$ = this.socketService.socket$
.map((action:BlogPayLoad)=>{
console.log(action)
return action
})
.mergeMap((action)=> {
if(action.type === 'BlogAddAction'){
return new fromBlogActions.BlogAddAction(action))
else if (...) {
....
}
else if (action.type === 'BlogUpdatedAction'){
return new fromBlogActions.BlogUpdatedAction(action))
})
I am very new Rxjs observable and need help with two questions.
I have this piece of code:
const resultPromise = this.service.data
.filter(response => data.Id === 'dataResponse')
.filter((response: dataResponseMessage) => response.Values.Success)
.take(1)
.timeout(timeoutInSeconds)
.map((response: dataResponseMessage) => response.Values.Token)
.toPromise();
I have following basic questions:
1- How can I change .timeout(timeoutInSeconds) to add a message so that I can debug/log later which response it fails? I looked at .timeout syntax in rxjs and didn't see an option to include any message or something.
2-I know .filter((response: dataResponseMessage) => response.Values.Success) will filter to responses with response.Values.Success but is there a syntax where I can do like this for an observable:
const resultPromise = this.service.data
.filter(response => data.Id === 'dataResponse')
.magicSyntax((response: dataResponseMessage) => {
if (response.Values.Success) {
// do something
} else {
// do something else
}
});
Thank you so much in advance and sorry if these are basic/dumb questions.
First question
If you reach timeout the operator will return you an error which can be caught with .catch operator
const resultPromise = this.service.data
.filter(response => data.Id === 'dataResponse')
.filter((response: dataResponseMessage) => response.Values.Success)
.take(1)
.timeout(timeoutInSeconds)
.catch(e=>{
//do your timeout operation here ...
return Observable.Of(e)
})
.map((response: dataResponseMessage) => response.Values.Token)
.toPromise();
Second question simply replace magicSyntax with map or mergemap depends what you want to return from this operation. it is perfectly fine to do if in side the block.
I'm assuming you are using at least Rxjs version 5.5 which introduced pipeable operators. From the docs - these can "...be accessed in rxjs/operators (notice the pluralized "operators"). These are meant to be a better approach for pulling in just the operators you need than the "patch" operators found in rxjs/add/operator/*."
If you aren't using pipeable operators, instead of passing the operators to pipe() like I did below, you can chain them using the dot notation you use in your example.
I suggest referring to learnrxjs.io for some additional info about the operators in RxJS, paired with examples.
The RxJS team has also created a BETA documentation reference.
Explanation
I assumed the first filter is receiving the response and filtering by response.Id instead of data.Id. If that wasn't a typo, you can keep the filter the same.
I added an extra line between the operators for presentation only.
mergeMap is an operator that takes a function that returns an Observable, which it will automatically subscribe to. I'm returning of() here, which creates an Observable that just emits the value provided to it.
catch was renamed to catchError in RxJS 5.5, and pipeable operators were also added, which add support for the .pipe() operator.
If you don't want to do anything besides logging the error, you can return empty(), which will immediately call complete() on the source Observable without emitting anything. EMPTY is preferred if you are using version 6.
Optional: Instead of using filter() and then take(1), you could use the first() operator, which returns a boolean, just like filter(), and unsubscribes from the source Observable after it returns true once.
import {EMPTY, of} from 'rxjs';
import {catchError, filter, take, mergeMap, timeout} from 'rxjs/operators';
const resultPromise = service.data.pipe(
// I assumed you meant response.Id, instead of data.Id
filter((response: dataResponseMessage) => response.Id === 'dataResponse'),
take(1),
// mergeMap accepts a value emitted from the source Observable, and expects an Observable to be returned, which it subscribes to
mergeMap((response: dataResponseMessage) => {
if (response.Values.Success) {
return of('Success!!');
}
return of('Not Success');
}),
timeout(timeoutInMilliseconds),
// catch was renamed to catchError in version 5.5.0
catchError((error) => {
console.log(error);
return EMPTY; // The 'complete' handler will be called. This is a static property on Observable
// return empty(); might be what you need, depending on version.
})
).toPromise();
1- you can use .do() to console.log your response.
.filter(..).do(response => console.log(response))
2- you can use .mergeMap()
I think I must be misunderstanding something fundamental, because in my mind this should be the most basic case for an observable, but for the life of my I can't figure out how to do it from the docs.
Basically, I want to be able to do this:
// create a dummy observable, which I would update manually
var eventObservable = rx.Observable.create(function(observer){});
var observer = eventObservable.subscribe(
function(x){
console.log('next: ' + x);
}
...
var my_function = function(){
eventObservable.push('foo');
//'push' adds an event to the datastream, the observer gets it and prints
// next: foo
}
But I have not been able to find a method like push. I'm using this for a click handler, and I know they have Observable.fromEvent for that, but I'm trying to use it with React and I'd rather be able to simply update the datastream in a callback, instead of using a completely different event handling system. So basically I want this:
$( "#target" ).click(function(e) {
eventObservable.push(e.target.text());
});
The closest I got was using observer.onNext('foo'), but that didn't seem to actually work and that's called on the observer, which doesn't seem right. The observer should be the thing reacting to the data stream, not changing it, right?
Do I just not understand the observer/observable relationship?
In RX, Observer and Observable are distinct entities. An observer subscribes to an Observable. An Observable emits items to its observers by calling the observers' methods. If you need to call the observer methods outside the scope of Observable.create() you can use a Subject, which is a proxy that acts as an observer and Observable at the same time.
You can do like this:
var eventStream = new Rx.Subject();
var subscription = eventStream.subscribe(
function (x) {
console.log('Next: ' + x);
},
function (err) {
console.log('Error: ' + err);
},
function () {
console.log('Completed');
});
var my_function = function() {
eventStream.next('foo');
}
You can find more information about subjects here:
https://github.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/subject.md
http://reactivex.io/documentation/subject.html
I believe Observable.create() does not take an observer as callback param but an emitter. So if you want to add a new value to your Observable try this instead:
var emitter;
var observable = Rx.Observable.create(e => emitter = e);
var observer = {
next: function(next) {
console.log(next);
},
error: function(error) {
console.log(error);
},
complete: function() {
console.log("done");
}
}
observable.subscribe(observer);
emitter.next('foo');
emitter.next('bar');
emitter.next('baz');
emitter.complete();
//console output
//"foo"
//"bar"
//"baz"
//"done"
Yes Subject makes it easier, providing Observable and Observer in the same object, but it's not exactly the same, as Subject allows you to subscribe multiple observers to the same observable when an observable only send data to the last subscribed observer, so use it consciously.
Here's a JsBin if you want to tinker with it.
var observer = Observable.subscribe(
function(x){
console.log('next: ' +
var my_function = function(){
Observable.push('hello')
One of the way to update an observable.