How to subscribe and unsubscribe from EventStream on the first event received? - bacon.js

I am trying to figure it out if there is a function in the Bacon.js API that allows to subscribe to an EventStream and when the first event fires up, the handle is unsubscribed. The way to do it that I know is the following:
let stream = new Bacon.Bus();
stream.onValue(val => {
doSomething(val);
return Bacon.noMore;
});
But is there something like stream.onValueOnce that automatically unsubscribe the handler after it is executed?
I also know that there is the Bacon.once that creates a EventStream that returns a single value and then ends the stream but this is not what I am looking for.
Update
As Bless Yahu sais, take or first methods can be used. To be more specific, you have to call it from the created eventStream like that:
let stream = new Bacon.Bus();
stream.first().onValue(val => {
doSomething(val);
});
Here is a fiddle that shows it:
https://fiddle.jshell.net/3kjtwcwy/

How about stream.take(1)? https://baconjs.github.io/api.html#observable-take
Or stream.first()? https://baconjs.github.io/api.html#observable-first

Related

what is the appropriate way to achieve offer to recieve and send in webRTC?

in my case after get everything done and running i want to migrate from add track to addTranciever
i have 2 peerConnection
yourConn = new RTCPeerConnection(servers);
yourConn2 = new RTCPeerConnection(servers);
and with following steps i see in many example casses i addTransciever like so
yourConn.addTransceiver(streams.getAudeoTracks()[0]);
how to recieve from yourConn peer ? and can i achieve that with send from peer 1 to peer 2
and p1 recieve from p2 with no need to negotiation again
what should i do also in ontrack event on both side with , should i use addTrack there or not if i wish
here yourConn2 event side here offer to send what about offer to recieve?
yourConn2.ontrack = (e) => {
e.transceiver.direction = 'sendrecv';
await e.transceiver.sender.replaceTrack(remoteStream);
};
should i grap
RemoteAudioFromlocal = yourConn2.getTransceivers()[0];
and i upgrade" the direction to sendrecv like so ?
RemoteAudioFromlocal.direction = "sendrecv"
await RemoteAudioFromlocal.reciever.replaceTrack(remotePeerStramIn);
i will answer my question since i figuer it out
from [Jan-Ivar Bruaroey blog1 i've discover all my question that i ask for
with addTransceiver() in one side i can get Transceivers within onTrackEvent
like so
if (e.transceiver.receiver.track) {
remoteVideo = document.getElementById("wbrtcremote");
transceiversRemotePeer = new MediaStream([e.transceiver.receiver.track]);
remoteVideo.srcObject = transceiversRemotePeer
}
that's all what i need to know the same on other side but here with a minor differnce like you need to change the direction since
The transceiver created by the sender is sendrecv by default with addtranciever
side
yourConn.addTransceiver(streams.getAudeoTracks()[0]);
. This gets mirrored by a transceiver on the receiver side for the same mid. Here it's exposed in the ontrack event,
yourConn2.ontrack = await e => {
/* do something with e.track */
e.transceiver.direction = 'sendrecv';
await e.transceiver.sender.replaceTrack(receiverTrack);
};
but in an "offer to receive" use case you could obtain it via getTransceivers() or like above code with e.transceiver.sender
on the receiver side(yourConn2), the direction is "downgraded" from sendrecv to recvonly because by default this transceiver is not configured to send anything back from receiverPc(yourConn2) to senderPc(yourConn).
After all, it was just created in response to setRemoteDescription(offer).
To fix this, you "upgrade" the direction to sendrecv and set a track to send.
e.transceiver.direction = 'sendrecv';
e.transceiver.sender.replaceTrack(localStream.getAudioTracks()[0]).then(() => {
});
If you do this prior to creating the local SDP answer on receiverPc, you should be able to achieve "sendrecv" without more SDP negotiations. The ontrack event is fired before the SRD promise is resolved, so any modification you do in that event should have completed before the SDP answer is created.

How to ignore vscode events from firing within a certain time interval?

For example, if I trigger onDidChangeTextDocument events consecutively, with an interval of at maximum 1 second, then I would like to avoid this event's associated logic.
However, if 1 second has passed since the lastest onDidChangeTextDocument has been triggered, I would like for it to proceed with its logic.
This approach is known as "coalescing events". A typical approach is to start a timer when an event appears with the required interval. Every new event restarts the timer, so it never triggers unless there are no new events within the timer value. The triggered timer then calls any further code, handling the coalesced events. This might cause some problems if you have to process all data sent by each event. In that case you have to collect that data on each invocation of your event handler.
Here's code to handle changes per file in a VS Code extension:
private changeTimers = new Map<string, ReturnType<typeof setTimeout>>(); // Keyed by file name.
workspace.onDidChangeTextDocument((event: TextDocumentChangeEvent) => {
if (event.contentChanges.length > 0) {
const fileName = event.document.fileName;
const timer = this.changeTimers.get(fileName);
if (timer) {
clearTimeout(timer);
}
this.changeTimers.set(fileName, setTimeout(() => {
this.changeTimers.delete(fileName);
... your processing here
}, 1000));
}
});

Delete event not emitted

I'm using a basic Deepstream setup with RethinkDB, but for some reason the delete event is never emitted when a record is deleted?
var x = window.deepstream.record.getRecord('test1');
x.subscribe(function(){
console.log('was deleted')
})
window.setTimeout(function(){
console.log('deleting');
x.delete();
},2000);
The "something happened" text never ouputs... Is this expected behavior?
It looks like subscribe does not actually listen for the delete event, I needed to specifically do:
x.on('delete', function(){
console.log('was deleted')
})

redux-observable return multiple action types

I am using redux-observable and this is what I am trying to do.
When an actiontype of 'APPLY_SHOPPING_LIST' comes in dispatch 'APPLYING_SHOPPING_LIST' and after 5 seconds dispatch 'APPLIED_SHOPPING_LIST'. This is the code that I have come up with so far
const applyingShoppingListSource = action$.ofType('APPLY_SHOPPING_LISTS').mapTo({ type: 'APPLYING_SHOPPING_LISTS' });
const applyingShoppingListSourceOther = action$.ofType('APPLY_SHOPPING_LISTS').mapTo({ type: 'APPLIED_SHOPPING_LISTS' }).delay(5000);
const concatList = applyingShoppingListSource.concat(applyingShoppingListSourceOther);
return concatList;
Now the problem is that only 'APPLYING_SHOPPING_LISTS' gets fired, the 'APPLIED_SHOPPING_LISTS' does not get fired to the reducer at all. Am I missing something here?
Just to add to this, when I used flatMap it worked, given below is the code
return action$.ofType('APPLY_SHOPPING_LISTS')
.flatMap(() => Observable.concat(Observable.of({ type: 'APPLYING_SHOPPING_LISTS' }), Observable.of({ type: 'APPLYING_SHOPPING_LISTS' });
I am confused how this works and the other does not?
There's a couple issues. Since Observables are lazy, your second action$.ofType('APPLY_SHOPPING_LISTS') for applyingShoppingListSourceOther is being concat'd after the first applyingShoppingListSource, so it won't be listening for APPLY_SHOPPING_LISTS until after the first one is has completed, but it will never realistically complete because you're taking all actions that match, forever.
Said another way, your code does this:
Start listening for APPLY_SHOPPING_LISTS and when received map it to APPLYING_SHOPPING_LISTS
When that first Observable completes (it never does) start listening for APPLY_SHOPPING_LISTS again, this time when received map it to APPLIED_SHOPPING_LISTS but wait 5000 ms before emitting it.
You could solve the particular issue of the first not ever completing by using .take(1) or .first() (same thing), but you usually need to write your epics to not ever stop listening so they respond to actions at any time.
I think what you want is this:
const exampleEpic = action$ =>
action$.ofType('APPLY_SHOPPING_LISTS')
.mergeMap(() =>
Observable.of({ type: 'APPLYING_SHOPPING_LISTS' })
.concat(
Observable.of({ type: 'APPLIED_SHOPPING_LISTS' })
.delay(5000)
)
);
I used mergeMap but you may want to use switchMap to cancel any previously pending APPLIED_SHOPPING_LISTS that haven't emitted yet. Your call.

cy.on('select') callback only once

I have a createTable function that receives a collection of nodes (or an array of nodes), then I am able to draw a table.
I am switching to cytoscape.js now, and I really don't know how to have a listener to my select event properly.
Doing this:
cy.on('select', 'node', function(event){
window["selectedNodes"] = cy.$('node:selected');
});
I do have all information I need to draw my table, but I cannot call my createTable function inside it because it will call my function several times (once per node selected).
I've already tried to use cy.on and cy.once, but without success.
Here is my question:
How can I have a listener to my selection event, get ALL selected nodes and call (only once) my createTable function ?
I can also obtain all selected node using this:
cy.elements('node:selected', console.log("my CallBack function"));
But as it is outside an event listener (select / click) it doesn't work as I need.
Please, any help is appreciated.
Thank you.
Debounce your callback so if multiple events come in one after another, then they are effectively batched:
var timeout;
cy.on('select', 'node', function(event){
clearTimeout( timeout );
timeout = setTimeout(function(){
window["selectedNodes"] = cy.$('node:selected');
// and so on...
}, 100); // may have to adjust this val
});