简体   繁体   中英

Can't add to an array with Javascript inside a for loop

I'm trying to write some code to find all the linked images on a webpage. So far I'm able to generate an array of all the links (imageLinks) but in the code below the final console.log(linkedImages) always shows an empty array.

The thing I can't wrap my head around is where I've commented "This works / But this doesn't work:"

What am I doing wrong? Any help is greatly appreciated for this somewhat noob. Thanks!

//Create an array of all the links containing img tags
var imageLinks = $("img").parent("a").map(function () {
    var h = $(this).attr("href");
    return h;
}).get();
//This correctly shows all the links:
//console.log(imageLinks);
//Declare an array to hold all the linked images 
var linkedImages = [];
//Loop through all the links to see if they're images or not
for (var l = 0; l < imageLinks.length; l++) {
    var currLink = imageLinks[l];

    function myCallback(url, answer) {
        if (answer) {
            //This works:
            console.log(url + ' is an image!');
            //But this doesn't work
            linkedImages.push(url);
        } else {
            //alert(url+' is NOT an image!');
        }
    }

    function IsValidImageUrl(url, callback) {
        var img = new Image();
        img.onerror = function () {
            callback(url, false);
        }
        img.onload = function () {
            callback(url, true);
        }
        img.src = url
    }
    IsValidImageUrl(currLink, myCallback);
};
//HELP! This always evaluates as just "[]"
console.log(linkedImages);

What @SLaks said. Since the loading of images is async, your callback doesn't fire until after the images have been loaded. To fix the problem, you can use $.Deferred from jQuery (I am assuming you are using jQuery since there is a $(...) in your code):

    function callback(dfd, url, answer) {
        if (answer) {
            //This works:
            console.log(url+' is an image!');
            //But this doesn't work
            dfd.resolve(url);
        } else {
            //alert(url+' is NOT an image!');
            dfd.reject();
        }
    }

    //Create an array of all the links containing img tags
    var imageLinks = $("img").parent("a").map(function() {
        var h = $(this).attr("href");
        return h;
    }).get();

    //This correctly shows all the links:
    //console.log(imageLinks);

    //Declare an array to hold all the linked images 
    var linkedImages = [];

    //Loop through all the links to see if they're images or not
    var dfds = [];
    for (var l=0; l<imageLinks.length; l++) {
        var currLink = imageLinks[l];
        var dfd = $.Deferred();
        dfd.done(function(url) { linkedImages.push(url); });
        dfds.push(dfd.promise());

        (function(dfd, url) {
            var img = new Image();
            img.onerror = function() { callback(dfd, url, false); }
            img.onload =  function() { callback(dfd, url, true); }
            img.src = url
        })(dfd, currLink);
    };

    $.when.apply(null, dfds).done(function() {
         console.log(linkedImages);
    });

Have not tested this, but the general idea for how to use deferred to reach your goal is in there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM