'equivalent of tap operator that waits for completion
I need to open a page on a URL, get the value of a variable, format it and return it.
I have this piece of code, which works :
async function fetchVariable(browser, url) {
const page = await browser.newPage();
await page.goto(url);
const s = await page.evaluate(async () => Promise.resolve(myVariable));
return s.replace(/\n/g, '');
}
I want to rewrite it without await because... why not. I tried this :
function fetchVariable(browser, url) {
return from(browser.newPage()).pipe(
tap(page => page.goto(url)),
mergeMap((page) => page.evaluate(async () => Promise.resolve(myVariable))),
map((s) => s.replace(/\n/g, ''))
).toPromise();
}
I am stuck on this part : tap(page => page.goto(url)), because tap will not wait before passing to the next operator. And it results in this error message :
UnhandledPromiseRejectionWarning: Error: Execution context was destroyed, most likely because of a navigation.
I basically need to get the page issued by browser.newPage(), wait for the page.gotoUrl(url) to complete and forward the page to the next operator.
It seems that I am lacking a basic operator but I cannot see which one.
Solution 1:[1]
Seeing that the goto return a Promise, I'd suggest you to go all in over RxJS and convert everything
function fetchVariable(browser, url) {
return from(browser.newPage()).pipe(
switchMap(page => // <-- use `switchMap` here
from(page.goto(url)).pipe( // <-- inner pipe to allow access to `page` variable
switchMap(page => from(page.evaluate)),
map(() => myVariable.replace(/\n/g, ''))
)
)
);
}
About toPromise(): it's being deprecated and will be removed by RxJS 8.
Solution 2:[2]
It sounds like you want to do "switchTap". Essentially perform an async side effect and wait for it to complete before continuing.
Instead of using tap, you could do switchMap, but return an observable that returns the original emission:
Here's a simplified example of the original situation:
const myObservable$ = of('source #1').pipe(
tap(() => myPromiseFn()),
switchMap(i => of('source #2'))
);
// Order:
// - source #1
// - source #2
// - promise
Solution mentioned above:
const myObservable$ = of('source #1').pipe(
switchMap(input => from(myPromiseFn()).pipe(
map(() => input)
)),
switchMap(i => of('source #2')),
);
// Order:
// - source #1
// - promise
// - source #2
Here's a little StackBlitz.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | ruth |
| Solution 2 | BizzyBob |
