1

I have made a class which builds some data from api:

const http = require("http");

class VideoService {

    constructor() {
        this.items = [];
    }

    fetchVideos(token = "") {

        const url = `https://www.example.com`;

        http.getJSON(url).then((results) => {
            results.items.forEach((item, index) => {
                const vid = item.snippet.resourceId.videoId;

                this.items.push({
                    title: item.title,
                    date: item.publishedAt
                });

                console.log(this.items.length); // here length inreases, works here
            });

            if (typeof results.nextPageToken !== "undefined") {
                return this.fetchVideos(results.nextPageToken);
            }

        });
    }

    getVideos() {
        this.fetchVideos();

        console.log(this.items.length); // this returns 0 instead of all items fetched

        return this.items;
    }

}

module.exports = VideoService;

In another file, I am using it like this:

const videoService = require("../shared/videoService");

const videos = (new videoService()).getVideos();
console.log(videos);

The last console.log call always returns empty array instead of all data collected in items property of the above class.

Can anybody tell what I am missing here?

dev0010
  • 95
  • 1
  • 5
  • 1
    Yeah so your function `fetchVideos()` has an http call which will be processed asynchronously. I suggest using something like a Promise or an Observable. You can read more about Promises here. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise – lloydaf Nov 22 '18 at 13:52
  • To elaborate: the calls to `.getJSON()` return immediately, *before* the response to the underlying HTTP request has been received. – Pointy Nov 22 '18 at 13:53
  • @Pointy: Thanks but I am rather new to promises stuff I cannot understand how to modify this code to use promises. I will love to see fix in an answer so I can accept it. Thanks – dev0010 Nov 22 '18 at 13:55
  • Your main issue is that you're not return a (resolved) Promise at the end of the recursion. – Alnitak Nov 22 '18 at 14:00
  • Maybe [the following answer](https://stackoverflow.com/a/53427061/1641941) can help you out in making requests based on result of previous request. – HMR Nov 22 '18 at 14:02
  • This answer help me resolve the issue: https://stackoverflow.com/a/53425714/8708756 – dev0010 Nov 22 '18 at 17:25

1 Answers1

1

This happens because in your function fetchVideos(), you are making an http call which will be processed asynchronously. You can try to process it this way.

fetchVideos(token = "") {

    const url = `https://www.example.com`;

    return http.getJSON(url).then((results) => {
        results.items.forEach((item, index) => {
            const vid = item.snippet.resourceId.videoId;

            this.items.push({
                title: item.title,
                date: item.publishedAt
            });

            console.log(this.items.length); // here length inreases, works here
        });

        if (typeof results.nextPageToken !== "undefined") {
            return this.fetchVideos(results.nextPageToken);
        }
        else return new Promise((resolve, reject)=>{
          resolve();
        });

    });
}

getVideos() {
    return this.fetchVideos().then(function(){
       console.log(this.items.length); // this returns 0 instead of all items fetched
    return this.items;
    });
}

I suggest reading about promises and asynchronicity in javascript. Check this link: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

lloydaf
  • 605
  • 3
  • 17
  • 1
    This is a good start, but things are much complicated by the fact that further HTTP requests are initiated in the callback in `fetchVideos()`. – Pointy Nov 22 '18 at 13:57
  • @Pointy nice catch. I did not notice that before. – lloydaf Nov 22 '18 at 14:00
  • @LloydFrancis: It still does not work as expected, console.log does not show any results. – dev0010 Nov 22 '18 at 14:05
  • 1
    The `fetchVideos` function is failing to return a Promise at the end of the chain of recursive calls – Alnitak Nov 22 '18 at 14:29