Closed vencho-mdp closed 2 years ago
However, when you want to get 60 items, you have to do ... Which isn't really DRY nor readable.
You could make a function that gets you 60 items. You could even make a function that gets you n
items.
Option 1
This is why it could be a nice feature to allow the items method to have a number param which could be the amount of items the user wants to get.
Take a look at Feed#items$
. With it you can do something like
feed.items$.pipe(mergeMap(x => x), take(60)) /* .subscribe(item => console.log(item)) */
// or
await firstValueFrom(feed.items$.pipe(mergeMap(x => x), take(60), toArray()));
The takeaway here is that items$
is an observable. You can even control how it polls the feed: here.
Also, it could be really good to allow the
items
method to have acondition
parameter.
That's really easy now. Just put a filter(fn)
in the pipe and you're ready to go.
Option 2
Make a wrapper function to convert the feed into an async iterator:
async function* feedToIterator<T>(feed: Feed<any, T>) {
do {
const items = await feed.items();
yield items;
} while(feed.isMoreAvailable());
}
Then you can use transformers acting on async iterables (or iterator helpers once they are in V8 and Node).
So for example flatten and filter:
async function* flatten<T>(iter: AsyncIterable<T[]>) {
for await(const items of iter) {
yield* items;
}
}
async function* filter<T>(iter: AsyncIterable<T>, fn: (item: T) => boolean) {
for await(const item of iter) {
if(fn(item)) yield item;
}
}
Then you can do something like:
for await(const item of filter(flatten(feedToIterator(feed)), myFn)) {
console.log(item);
}
Thanks for the reply! And how would you combine both? (function that takes the first n number of items that satisfy a condition) @Nerixyz
ANd how would you combine both?
Observables
feed.items$.pipe(mergeMap(x => x), filter(myFn), take(60))
AsyncIterables
You'd need an additional take
:
async function *take<T>(iter: AsyncIterable<T>, n: number) {
if(n <= 0) return;
let i = 0;
for await(const item of iter) {
yield item;
i++;
if(i >= n) break;
}
}
If you want to put it in an array you also need a function toArray
:
async function toArray<T>(iter: AsyncIterable<T>) {
const arr = [];
for await(const item of iter) {
arr.push(item);
}
return arr;
}
Then it's
const items = await toArray(take(filter(flatten(feedToIterator(feed)), myFn), 60));
I prefer the observables for now since they are easier to read and rxjs is already a dependency of the library.
Oh, and mergeMap, take, filter
are all functions from rxjs
?
Oh, and
mergeMap, take, filter
are all functions fromrxjs
?
Right all of them are in rxjs/operators
.
I'm getting the following error:
TypeError: iter is not iterable
Do you know why it could be?
(I'm using the AsyncGenerators solution) @Nerixyz
I guess you're trying to directly pass the feed to flatten/filter/...
You need to "convert" the feed into an async iterater/iterable. So you need to pass it into feedToIterator
. If that doesn't help, try to find which object isn't iterable.
The object which is not iterable is from this function: feedToIterator
Did you put the *
after the function
keyword?
Yes, I copy paste the code
I don't see any error. This works for me:
Maybe it's because I'm using JS and I changed it wrongly. Could you provide a javascript Version?
Feature Request
Form
Put an
[x]
if you meet the condition, else leave[ ]
.Description
A specific description of your feature, so it's understandable to anyone. You can add pictures.
Now, you have to use
.items()
method to get 12 items and, as far as I know, there isn't any other way. However, when you want to get 60 items, you have to doWhich isn't really DRY nor readable. This is why it could be a nice feature to allow the
items
method to have a number param which could be the amount of items the user wants to get. Also, it could be really good to allow theitems
method to have acondition
parameter. It'd work the following way: When the method gets N (default: 12) quantitity of items that satisfy that condition, then the promise resolves.