[英]Async in RxJS Observable
第一次使用RxJS。 基本上,我正在嘗試制作一個Twitter抓取程序,以從查詢字符串中檢索推文。 搜索網址允許指定min_position參數,該參數可以是上一次進行分頁的搜索的最后一個id。
該過程看起來像這樣(最后循環返回):
get page -> next() each scraped tweet -> set min_position -> get page (until !has_more_items)
請求頁面會返回一個承諾,因此我必須以某種方式等到完成為止才能繼續。 我希望將異步函數傳遞給Observable.create()
但這似乎不起作用,它僅被稱為一次。
編輯
盡我所能閱讀您的資源后,我一直在玩耍。 我提出了以下問題的抽象概念。
import { from, Observable } from 'rxjs'
import { concatMap, map, switchMap } from 'rxjs/operators'
let pageNumber = 0
const PAGE_SIZE = 3, MAX_PAGES = 3
async function nextPage() {
if (pageNumber >= MAX_PAGES) {
throw new Error('No more pages available')
}
await new Promise(res => setTimeout(res, 500)) // delay 500ms
const output = []
const base = pageNumber++ * PAGE_SIZE
for (let i = 0; i < PAGE_SIZE; i++) {
output.push(base + i)
}
return output
}
function parseTweet(tweet: number): string {
// simply prepend 'tweet' to the tweet
return 'tweet ' + tweet
}
const getTweets = (): Observable<string> => {
return from(nextPage()) // gets _html_ of next page
.pipe(
concatMap(page => page), // spreads out tweet strings in page
map(tweet => parseTweet(tweet)), // parses each tweet's html
switchMap(() => getTweets()) // concat to next page's tweets
// stop/finish observable when getTweets() observable returns an error
)
}
getTweets()
.subscribe(val => console.log(val))
它已經接近工作了,但是現在無論何時nextPage()
返回被拒絕的承諾,整個可觀察的中斷(什么都不會記錄到控制台)。
我試圖在pipe
后插入catchError
來完成可觀察的操作,而不是通過運行並拋出錯誤,但是我無法使其正常工作。
同樣,該實現是遞歸的,我希望避免這種實現,因為它不可擴展。 我不知道將來會觀察到多少條推文/頁面。 似乎還必須處理所有3頁上的推文,然后可觀察對象開始發出值,這當然不是它應該如何工作的。
謝謝你的幫助! :)
我們需要加載Twits,直到某些情況出現並以某種方式與Promise合作? 看一個例子:
function loadTwits(id) {
// Observable that replay last value and have default one
twitId$ = new BehaviorSubject(id);
return twitId$.pipe(
// concatMap - outside stream emit in order inner do
// from - convert Promise to Observable
concatMap(id => from(fetchTwits(id))),
map(parseTwits),
// load more twits or comlete
tap(twits => getLastTwitId(twits) ? twitId$.next(getLastTwitId(twits)) : twitId$.complete())
)
}
在進一步研究expand
並意識到可觀察到的遞歸之后,我弄清楚了。 這是創建可觀察對象的代碼:
const nextPage$f = () => from(nextPage()) // gets _html_ of next page
.pipe(
concatMap(page => page), // spreads out tweet strings in page
map(tweet => parseTweet(tweet)) // parses each tweet's html
)
const tweets$ = nextPage$f()
.pipe(
expand(() => morePages() ? nextPage$f() : empty())
)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.