Reputation: 63
So I am relatively new to RxJs and Observable patterns in general and am currently struggling to understand some of the features provided and why they behave the way they do.
Here is a code snippet :
Observable.if( //can also be onErrorResumeNext
() => true,
Observable.fromPromise(
fetch('/'+ locale + '_state.json', {
headers: {
'Accept': 'application/json'
},
method: 'GET'
}).then(res => {
if (!res.ok) {
throw new Error(res.statusText);
}
return res.json();
})
),
Observable.fromPromise(
fetch('/'+ defaultLocale + '_state.json', {
headers: {
'Accept': 'application/json'
},
method: 'GET'
}).then(res => {
if (!res.ok) {
throw new Error(res.statusText);
}
return res.json();
})
)
)
Why do both of these statements gets executed? Am I doing something/approaching this in the wrong way or is this expected behaviour? Returning something more simple like in the example of Observable.if works fine, but as far as I understand RxJs is meant to be mainly for asynchronous data so should not the example above behave the same way?
I am aware I can rewrite the behaviours of Observable.if and Observable.onErrorResumeNext using Observable.mergeMap and thats what I ended up doing but it feels like I am missing something out here.
Upvotes: 1
Views: 72
Reputation: 20348
The thing is that promise
is not lazy and executes immediately. To easiest way to make a computation lazy is to use .defer
like that:
Observable.if( //can also be onErrorResumeNext
() => true,
Observable.defer(() =>
fetch('/'+ locale + '_state.json', {
headers: {
'Accept': 'application/json'
},
method: 'GET'
}).then(res => {
if (!res.ok) {
throw new Error(res.statusText);
}
return res.json();
})
),
Observable.defer(() =>
fetch('/'+ defaultLocale + '_state.json', {
headers: {
'Accept': 'application/json'
},
method: 'GET'
}).then(res => {
if (!res.ok) {
throw new Error(res.statusText);
}
return res.json();
})
)
)
.defer
will automatically upgrade a promise to an observable
.
Upvotes: 1
Reputation: 101730
You are calling fetch()
twice and passing the result to Observable.if()
. RxJs has no ability to control which one is called because you are already calling both before Observable.if()
even runs.
The second and third parameters of your Observable.if()
contain a lot of duplicate code. Why not rewrite this like so:
Observable.if(() => true, locale, defaultLocale)
.mergeMap(val =>
fetch('/'+ val + '_state.json', {
headers: {
'Accept': 'application/json'
},
method: 'GET'
}).then(res => {
if (!res.ok) {
throw new Error(res.statusText);
}
return res.json();
})
);
Upvotes: 1