简体   繁体   中英

RxJS Run Promise, then combineLatest

I apologize for so many observable questions lately, but I'm still having a really tough time grasping how to chain everything together.

I have a user, who is using promise-based storage to store the names of feeds they do not want to see. On the Social Feeds widget, they get to see the latest article from each feed that they have not filtered out.

I'd like to take a union on the hard-coded list of feeds and the feeds they want to hide. To work with the API I've been given, I need to make multiple calls to the service to retrieve each feed individually.

After I make that union, I'm looking to combine, sequentially, the observable that the utility getFeed method produces.

Here's what I'm looking to do with some pseduocode.

/**
 * This gets the top items from all available social media sources.
 * @param limit {number} The number of items to get per source.
 * @returns {Observable<SocialItem[]} Returns a stream of SocialItem arrays.
 */
public getTopStories(limit: number = 1): Observable<SocialItem[]> {

    // Merge the list of available feeds with the ones the user wants to hide.
    const feedsToGet = this.storage.get('hiddenFeeds')
        .then(hiddenFeeds => _.union(FeedList, hiddenFeeds));

    // Let's use our function that retrieves the feeds and maps them into an Observable<SocialItem[]>.
    // We need to splice the list because only 'limit' amount of articles can come back from each feed, and the API cannot accommodate sending anything else than 25 items at a time. 
    // We need to do mergeMap in order to return a single array of SocialItem, instead of a 2D array.
    const feeds$ = feedsToGet.map(feed => this.getFeed(feed).map(res = res ? res.slice(0, limit) : []).mergeMap(val => val));

    // Let's combine them and return
    return Observable.combineLatest(feed$);
}

Edit: Again, sorry for sparse code before.

The only issue with your example is that you are doing your manipulation in the wrong time frame. combineLatest needs an Observable array, not a Future of an Observable array, a hint that you need to combineLatest in the promise handler. The other half is the last step to coerce your Promise<Observable<SocialItem[]>> to Observable<SocialItem[]> , which is just another mergeMap away. All in all:

public getTopStories(limit: number = 1): Observable<SocialItem[]> {
    // Merge the list of available feeds with the ones the user wants to hide.
    const feeds_future = this.storage.get('hiddenFeeds')
        .then(hiddenFeeds => Observable.combineLatest(_.map(
          _.union(FeedList, hiddenFeeds),
          feed => this.getFeed(feed).mergeMap(res => res ? res.slice(0, limit) : [])
        ))); // Promise<Observable<SocialItem[]>>

    return Observable.fromPromise(feeds) // Observable<Observable<SocialItem[]>>
                     .mergeMap(v => v); // finally, Observable<SocialItem[]>
}

PS the projection function of mergeMap means you can map your values to Observables in the same step as they are merged, rather than mapping them and merging them separately.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM