I like the readability provided by
observable
.pipe(operator1)
.pipe(operator2)
.pipe(operator3)
.subscribe()
And it reminds me of a chain of thens for a promise.
But I know this is in every documentation example
observable
.pipe(
operator1,
operator2,
operator3
).subscribe()
Is there something lost in doing the first thing over the second? I am probably missing some crucial information here and maybe it's very obvious, actually. Thanks for the help.
certainly they are equal and they have same result.
both of them is equal to
operator3(operator2(operator1(observable))).subscribe()
Related
observable1.pipe(
withLatestFrom(observable2),
.. do something with both emitted observable values
)
Problem with withLatestFrom is that if observable2 hasn't emitted any event before the observable1 did then it's a dead code. How should I modify the code to ensure that do something with both emitted observable values will have have both observable values emitted at least once prior to the call? Maybe some wrapper around the forkJoin?
You could use the RxJS combineLatestWith if you're looking for a pipable operator instead of combineLatest function.
observable1.pipe(
combineLatestWith(observable2),
// ... do something with both emitted observable values
)
Looks like a use case for the combineLatest operator. This operator takes an array of observables and waits for every to emit at least once. Once all the observables have emitted, the operator emits for the first time. After that it emits every time any of the observables emits.
You can enforce a first emission with startWith(), you apply it to both observable 1 and 2 depends on your need.
observable1.pipe(
withLatestFrom(observable2.startWith(null)),
.. do something with both emitted observable values
)
NgRx provides a concatLatestFrom operator implementation you can reference. It wraps withLatestFrom to produce the behavior that you (and very many others) are expecting and is potentially more semantically clear than combineLatestWith. This also works on versions RxJS before 7:
source1$.pipe(
concatLatestFrom(source2$),
...
)
This question is for learning purposes, not to solve a particular problem (please move it to the appropriate section if necessary).
I'm learning about piping operators in the RxJS library. At this site here (https://rxjs.dev/guide/operators) it distinguishes between pipeable operators and creator operators.
It defines pipeable operators as follows:
A Pipeable Operator is a function that takes an Observable as its input and returns another Observable. It is a pure operation: the previous Observable stays unmodified.
And it defines creator operators as follows:
Creation Operators are the other kind of operator, which can be called as standalone functions to create a new Observable. For example: of(1, 2, 3) creates an observable that will emit 1, 2, and 3, one right after another.
But this leaves me wondering: is there such an operator as one that DOES modify the observable it gets as input and returns it as output? I haven't come across anything like that. Is there a reason such an operator doesn't exist? What kind of undesired behavior would result from such an operator?
You can see pipable operation as a series of function execution, in most of the time there's no need for modifying the upstream function. What we interest in is transforming data and add custom operation as we proceed down the stream
fn(fn2(fn3(...)))
if in any case you want to modify upstream behavior, the upstream observable has to be designed to allow such case, for instance use a function factory to let user add an middleware
e.g
const interceptor=()=>{...}
const getUpstreanFn=(middleware)=>(param)=>{ middleware()......}
const upstreamFn=getUpstreamFn(middleware)
i am trying to 'think in streams'. What is the correct way to emit a value to stream B after stream A has completed?
my current implementation is as follows:
streamADelete$(data)
.do(() => dismiss())
.subscribe(() => streamB$.next()) // this seems wrong!
to me there is something wrong with this implementation
If your main goal is to call streamB.next(), but somewhere before the subscribe block, then the correct place to do that would be the tap() operator, which is meant for doing side-effects.
streamADelete$(data)
.pipe(
tap(() => streamB$.next()),
// Continue with your next operator
)
This does seem like a strange thing to do though, we are usually able to achieve most things without doing side-effects. I am not exactly sure what your use-case is, but another pattern that might be helpful could be to split your stream into two like this:
streamADelete$.pipe(
// Do whatever you want to do in your original stream here
)
.subscribe();
streamADelete$.pipe(
// Do whatever you wanted to do in you streamB$ stream here
)
.subscribe();
(Your RxJS also seems a little strange, are you using an old version of RxJS / following some old tutorials?)
The documentation isn't helpful enough for me to understand the difference between these.
It's like concatMap, but maps each value always to the same inner
Observable.
http://reactivex.io/rxjs/file/es6/operators/concatMapTo.js.html
I tried checking out learnrxjs.io's examples on stackblitz, but even with those, I wasn't able to immediately identify what the distinguishing feature was separating these.
FYI i saw this other similar question
What is the difference between mergeMap and mergeMapTo?
but the answer in there wasn't satisfactory, because in the learnrxjs.io examples, they clearly map to observables, not hard-coded values.
https://www.learnrxjs.io/operators/transformation/concatmapto.html
If someone could provide some examples (and maybe a brief explanation) to help distinguish the *** vs the ***To higher-order observable operators, I'd appreciate that, thanks.
Simply said, variants with *To will always use the same Observable that needs to be created when the whole chain is created regardless of the values emitted by the chain. They take an Observable as a parameter.
Variants without *To can create and return any Observable only when their source Observable emits. They take a callback as a parameter.
For example when I use mergeMapTo I'm always subscribing to the same Observable:
source.pipe(
mergeMapTo(of(1)),
)
Every emission from source will always be mapped to of(1) and there's no way I can change that.
One the other hand with just mergeMap I can return any Observable I want depending on the value received:
source.pipe(
mergeMap(v => of(v * 2)),
)
Maybe an easier way to think about this is to remember that *To variants map a value to a constant (even when it's not a "real JavaScript constant").
Explaine me, please, what is the difference between those three variants of code? They all are working well.
Or maybe the first and second variant are identical?
What about the third one: I read that "browser.sleep()" is better to avoid in code, as it cause unstabilities in tests work. Is it true?
Help me to understand.
Thanks.
var MenuSigninButton = $('button.btn');
var LoginDropdownForm = element(by.id('loginForm'));
MenuSigninButton.click();
browser.wait(EC.visibilityOf(LoginDropdownForm));
and
MenuSigninButton.click();
browser.wait (function () {
return LoginDropdownForm.isDisplayed()
});
and
MenuSigninButton.click();
browser.sleep(3000);
expect(LoginDropdownForm.isDisplayed()).toBe(true);
First of all, yes, you should avoid use driver.sleep() as long as you can. Why?
Well, if you started to use that is because you are waiting something to appear on the screen in order to continue the execution of the test.
Well, you don't know how much time it will last that "something" to appear.
Maybe sometimes the time that you hardcoded is too short, and the test will fail, giving a fake result.
Maybe, the time is too long, and the test will last too much, and you could save that time.
Sometimes, the two points above could happen depending on time, overall load of the env,...
Second question:
When you use browser.wait(), you have to pass a condition to stop the wait.
It can be a Promise that will be solved on the future(not covered on your examples), it can be a condition(First example) or it can be a function, that has to be executed (Second example).
The third example is a bit different:
When you use the expect method, you are explicitly writing a condition that must pass in order to pass the test. For that reason, expect does not ends until the Promise inside it is resolved.