0

I have an array full of video objects. When I print them to the console, there are 30 elements - each an expected video object with the appropriate information. However, when I try to print an individual element of that array to the console, the console simply reads "undefined". Correspondingly, when I try to access the data of that element, an error is produced because the element is not defined. I'm using AJAX, but it should be noted that every single promise is guaranteed to be resolved by the time this function is called. Additionally, this is the very last part of the code. As such, I can't imagine how the array's contents would be changing. (And given that these are consecutive lines of code, it would additionally be surprising if this change was so reliable as to always happen between these two lines, even if it's something occurring asynchronously.)

The code:

var allVideoPromises = [];
Object.keys(channels).forEach((channelName) => {
    var channel = channels[channelName];
    channel.uploadsPromise.then(function(data) {
        var videoList = JSON.parse(data);
        var channelPromises = [];
        for (var videoData in videoList.items) {
            var video = new YouTubeVideo(videoList.items[videoData].contentDetails.videoId, channel);
            channel.uploads.push(video);
            videos.push(video);
            channelPromises.push(video.videoPromise);
            allVideoPromises.push(video.videoPromise);
            video.videoPromise.then(function(data) {
                var data = JSON.parse(data);
                if (data.items.length > 0) {
                    var videoData = data.items[0];
                    video.title = videoData.snippet.title;
                    video.thumbnail = videoData.snippet.thumbnails.default;
                    video.buffer = (video.thumbnail.height > 90) ? (90 - video.thumbnail.height) / 2 : 0;
                    video.date = new Date(videoData.snippet.publishedAt);
                    video.loaded = true;
                }
            }).catch(function(err) { console.log(err); })
        }
        Promise.all(channelPromises).then(function(data) {
            channel.uploads.sort(function(a, b) { if (a.date < b.date) return 1; else if (a.date > b.date) return -1; return 0; });
        }).catch(function(err) { console.log(err); });
    }).catch(function(err) { console.log(err); });
});


Promise.all(allVideoPromises).then(function(data) {
    videos.sort((a, b) => a.date < b.date);
    console.log(videos);
    console.log(videos[0]);
    //setVideo(mostRecent, video);
}).catch(function(err) { console.log(err); });

The output:

enter image description here

enter image description here

I have no clue what could be the issue here. It seems like the issue must be a basic JavaScript Issue, but in case it ends up being something else: I'm using HTML, CSS, JS, AJAX, and just enough JQuery to make these AJAX calls. I'm also using Google's YouTube API (v3), if that matters somehow. I'm not even using HTTP/HTTPS, as I'm just using this locally as a custom homepage. Any help would be appreciated.

Anslean
  • 19
  • 1
  • 5
  • 1
    FYI your sorting function is incorrect: `(a, b) => a.date < b.date` doesn't return -1, 0, or 1 as required for `.sort()`. Instead, it returns a boolean. See https://stackoverflow.com/questions/24080785/sorting-in-javascript-shouldnt-returning-a-boolean-be-enough-for-a-comparison – Sash Sinha Aug 28 '23 at 00:00
  • 3
    Where is the `videos` variable defined? – Derek Aug 28 '23 at 00:03
  • 3
    Why do you not use the `data` variable as defined by your `.then()` handler? – Daedalus Aug 28 '23 at 00:04
  • @SashSinha I just changed that. Unfortunately, it turns out it's not the core of my issue. Thanks for catching that, though. @Derek I mean, it's a few hundred lines of code upward (on the global scope) at the beginning of the code. It's definitely defined as an array. @Daedalus I've already handled the data in `.then()` calls on each promise individually. I don't need to receive data anymore, I just need to ensure all the data is available. I'm not sure if I need to include the argument anyway, or if I can get rid of it - I just hadn't gotten around to looking it up quite yet. – Anslean Aug 28 '23 at 00:11
  • @Daedalus it occurs to me that this is not an effective way of ensuring that the previous `.then()`s have finished, just that they're allowed to start. Given that the video data seemed to consistently be available at the time of this code's execution, I would not anticipate this being relevant. However, it seems closer to being relevant than anything else I can think of. So hopefully there's a connection here. – Anslean Aug 28 '23 at 00:25
  • 1
    you have two output pictures - the second seems to be the two `console.log`s in the code you posted ... what is the first picture of? – Jaromanda X Aug 28 '23 at 00:25
  • 1
    what are the `previous .then()`? you've posted code with **exactly one** `.then` ... so, there are no previous `.then` - maybe the code that produces the array of promises in `allVideoPromises` is at fault – Jaromanda X Aug 28 '23 at 00:27
  • @JaromandaX the same array as in the second picture, but with the array of videos expanded to demonstrate the data is there (rather than undefined) – Anslean Aug 28 '23 at 00:27
  • 1
    oh, if you `console.log(videos.length)` instead of `console.log(videos)`, what is the output - I really suspect that `videos` is an empty array at this point possibly because of code you haven't shown, i.e. what creates the `allVideoPromises` promises - you probably did that wrong – Jaromanda X Aug 28 '23 at 00:29
  • 2
    what does `videos` have anything to do with the promise? – epascarello Aug 28 '23 at 00:29
  • @Anslean - that was me that suggested that ... you're doing something wrong in code you haven't shown ... at a guess, there's a `return` missing in a `.then` (not the one you've shown) – Jaromanda X Aug 28 '23 at 00:31
  • data is the request of all your promises.... are you supposed to be looping over that? You need to show more code. – epascarello Aug 28 '23 at 00:31
  • @JaromandaX Oh, I didn't think to consider that. It returns a length of zero. I'll see what else I can dig up that might be relevant. – Anslean Aug 28 '23 at 00:32
  • 1
    the relevant code would be the code that creates the `allVideoPromises` and how that code is responsible for creating data in the mystery `videos` variable – Jaromanda X Aug 28 '23 at 00:34
  • @epascarello there are other `.then()` calls on individual promises, which populate the video array. I am using this `.all(allVideoPromises).then()` call to ensure the other `.then()` calls have all had a chance to process. I understand this isn't exactly correct, my conversation with Jaromanda addresses this to some degree. I gave all the code that seemed relevant at the time. I can add more code, but it's going to take me a bit to sort out which code is relevant. – Anslean Aug 28 '23 at 00:37
  • well with what you gave it is impossible for us to guess at what your problem is – epascarello Aug 28 '23 at 00:38
  • 1
    `which code is relevant` - the code that creates the `allVideoPromises` array and how that code is responsible for populating the data in the mystery `videos` variable – Jaromanda X Aug 28 '23 at 00:39
  • @JaromandaX I think I have what's needed now. Does that look right/helpful? – Anslean Aug 28 '23 at 00:43
  • 1
    ahh, yes, `allVideoPromises` is empty when you use `Promise.all(allVideoPromises)` - because it is populated inside `.then` – Jaromanda X Aug 28 '23 at 00:44
  • @JaromandaX Oh, I see. I'm still a bit confused at the video array starting as populated but then becoming unpopulated, rather than simply being unpopulated from the start. But maybe I'll wrap my head around it as I fix the issue you identified. Thanks! – Anslean Aug 28 '23 at 00:52
  • 1
    `starting as populated` - where? - oh, you mean that in the console you can see `videos` has items in it ... that's because the console evaluates the object when you view it in the console - by then the asynchronous part has completed I guess, so, it is populated in the console, but since `video.length` is zero in the original code you posted, that's the length when the code is executed (.length is a primitive, not an object, so the console gets that right) – Jaromanda X Aug 28 '23 at 00:54
  • @JaromandaX Oh, so it's because the console receives references rather than values? It's such a wild result when you don't know those little details, but it makes so much sense with that in mind. – Anslean Aug 28 '23 at 00:59
  • 1
    As I like to put it .. *the console lies* ... I mean, it doesn't, but it can fool you :p – Jaromanda X Aug 28 '23 at 01:09

0 Answers0