Hey guys ! π
Hope you are doing well π€
And Happy Thanks giving ππ¦
Yesterday, just wrote a short article about Create our own iterable in JavaScript, please make sure to check last sniped code there, because we are going to update it to asynchronous object here π
Today we are going to make that simple interable object more useful π
We have some operators like forkJoin from rxjs, that will let us to complete array of observable objects ( maybe it's good subject to write short article about π€)
That is really use full feature when we are going to fetch multiple data from multiple sources π
Update is simple, first let's see how our iterable object look's like
const ourOwnIterable = {
value: [1, 2, 3, 4, 5],
index: 0,
[Symbol.iterator]() {
return {
next: () => {
if(this.value.length === this.index) {
return {
value: null,
done: true
}
}
this.index++;
return {
value: this.value[this.index - 1],
done: false
}
}
}
}
}
And we was able to go throw values using for-of loop like so
for (const el of ourOwnIterable) {
console.log(el)
}
Let's clear our scenario, we are going to have some URLs to retrieve some data from and have the ability to go throw them one by one and see the result for each one of them π
First we are going to use URLs instead of values
const ourOwnIterable = {
urls: [],
...
Then we are going to use asyncIterator
method of Symbol
instead of iterator
....
[Symbol.asyncIterator]() {
return {
....
As we are going to use fetch
for calling our URLs, and await
operator, we need to update our next()
function, and decorate it with async
prefix
...
return {
next: async () => {
...
Now we are ready to implement our logic to retrieve, extract and return data from URLs
next: async () => {
if (this.urls.length === this.index) {
return {
value: null,
done: true
}
}
this.index++;
const fetchedResult = await fetch(this.urls[this.index - 1]);
const extractedData = await fetchedResult.json();
return {
value: extractedData,
done: false
}
}
It can be good practice to put our fetch solution inside try-catch
to have some error handling
try {
const fetchedResult = await fetch(this.urls[this.index - 1]);
const extractedData = await fetchedResult.json();
return {
value: extractedData,
done: false
}
} catch (e) {
return {
value: {
url: this.urls[this.index - 1],
error_message: `Got error ${e.message}`
},
done: false
}
}
Now our iterable object is ready to use with for-of loop π
for await (const res of ourOwnIterable) {
console.log(res);
}
Ok, let's put this for-loop inside some async function, pass some URLs and see what will happen ! π€ͺ
async function fetchAllUrls(urls) {
ourOwnIterable.urls = urls;
for await (const res of ourOwnIterable) {
console.log(res);
}
}
fetchAllUrls([
'https://jsonplaceholder.typicode.com/todos/1',
'https://jsonplaceholder.typicode.com/todos/2',
'https://jsonplaceholder.typicode.com/todos/3'
]);
To see the results we need to have some HTML document, as we are using fetch()
method (HTML API π€)
The desire out put will be something like this
Object { userId: 1, id: 1, title: "delectus aut autem", completed: false }
Object { userId: 1, id: 2, title: "quis ut nam facilis et officia qui", completed: false }
Object { userId: 1, id: 3, title: "fugiat veniam minus", completed: false }
And that's it π€ΈββοΈ
Now we have our own iterable object that can fetch array of URLs one by one with beautiful error handler
The final full script will be like this
const ourOwnIterable = {
urls: [],
index: 0,
/**
*
* @returns {{
* next: (function(): Promise<{value: null, done: boolean}
* |{value: any, done: boolean}
* |{value: {error_message: string, url: *}, done: boolean}
* |undefined>)}}
*/
[Symbol.asyncIterator]() {
return {
next: async () => {
if (this.urls.length === this.index) {
return {
value: null,
done: true
}
}
this.index++;
try {
const fetchRes = await fetch(this.urls[this.index - 1]);
const extractedData = await fetchRes.json();
return {
value: extractedData,
done: false
}
} catch (e) {
return {
value: {
url: this.urls[this.index - 1],
error_message: `Got error ${e.message}`
},
done: false
}
}
}
}
}
}
/**
*
* @param urls
* @returns {Promise<void>}
*/
async function fetchAllUrls(urls) {
ourOwnIterable.urls = urls;
for await (const res of ourOwnIterable) {
console.log(res);
}
}
fetchAllUrls([
'https://jsonplaceholder.typicode.com/todos/1',
'https://jsonplaceholder.typicode.com/todos/2',
'https://jsonplaceholder.typicode.com/todos/3'
]);
Thank you so much for your time π€
Hope you enjoyed β€
Top comments (0)