Let's create our own asynchronous iterator object
Tags: javascript, typescript
Published: 2020-11-27 20:35:49

Hey guys ! 👋
Hope you are doing well 🤞

And Happy Thanks giving 🎉🦃

Yesterday, just wrote a short article about [Create our own iterable in JavaScript](https://dev.to/ussdlover/create-our-own-iterator-in-javascript-3oe1), 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
```javascript
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

```javascript
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
```javascript
const ourOwnIterable = {
    urls: [],
    ...
```

Then we are going to use `asyncIterator` method of `Symbol` instead of `iterator`

```javascript
....
 [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

```javascript
...
return {
 next: async () => {
...
```

Now we are ready to implement our logic to retrieve, extract and return data from URLs

```javascript
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

```javascript
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 😄

```javascript
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 ! 🤪

```javascript
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

```javascript
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

```javascript
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 ❤