0

I'm pretty new to Javascript/jQuery so please bear with me. I am making a Chrome extension, and in the file content_script.js I am looping through a list of links and making ajax requests to determine which ones have a 404 status code. I am aware that the requests are made asynchronously, and I suspect this is the reason why, when I send a message containing an array from content_script.js to popup.js, the array is empty even though a console.log in content_script.js suggests otherwise.

I am curious how this is this possible if console.log in content_script.js (which came before the message was sent to popup.js) showed the array was populated? Should I be using a callback to solve this? I already tried setting ajax setting property async:false, but then my program did not console.log at all and appeared to be stuck waiting on the requests.

content_script.js

// var url = window.location.href;
var validLinks = new Array();
var array = new Array();

grabLinks();

for (var i=0;i<array.length;i++)
{
    $.ajax({
        url: array[i],
        statusCode:{
            404: function(){
                validateLink(array[i]);
            }
        }
    });
}
console.log(validLinks);//this shows me that the array IS populated
chrome.runtime.sendMessage({valid:validLinks}, function(response) {});
//but when I send the message, it is EMPTY in popup.js

function grabLinks(){
    //get all the links from the document
    let links = document.links;
    for (var i=0;i<links.length;i++)
    {
        array.push(links[i].href);
    }
}

function validateLink(link){
    //I check whether the link has been archived, and add it to an array if it has
    console.log("validating link");
    $.getJSON('http://archive.org/wayback/available?url=' + link,function(data){
        if (!$.isEmptyObject(data['archived_snapshots']))
        {
            let code = data['archived_snapshots']['closest']['status'];
            let oldUrl = data['archived_snapshots']['closest']['url'];
            console.log("pushing good url to array");
            validLinks.push(oldUrl);
        }
    });
}

popup.js

'use strict';
console.log("reached popup.js");
var searchBtn = document.getElementById("searchArchive");
var linkList = document.getElementById("fixedLinks");
searchBtn.addEventListener("click",function(){
    chrome.tabs.executeScript({file:'jquery-3.3.1.min.js'},function(){
        chrome.tabs.executeScript({
            file: 'content_script.js'
        });
    })
});

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
        let links = request.valid;
        console.log(links); //the requested array is now EMPTY
        console.log("populating link list");
        if (links.length==0)
        {
            linkList.innerHTML="no broken links were found";
        }
        for (var i=0;i<links.length;i++)
        {
            let a = document.createElement('a');
            console.log(links[a]);
            a.href = links[a];
            a.innerHTML = links[a];
            linkList.appendChild(a);
        }
  });
I Like
  • 1,711
  • 2
  • 27
  • 52

1 Answers1

0

You're right, it's not working because the ajax requests are asynchronous.

You need to run the chrome.runtime.sendMessage function after all of the ajax requests have finished (both the $.ajax ones and the $.getJSON ones). Count the number of completions, and proceed when it's equal to array.length.

To create a callback that always runs after $.ajax completes, use $.ajax(...).always(callbackFn)

Objects and arrays logged to the console can't be trusted, they show their current state in the console - not the state they were in when you logged them. To fix it, either convert the array to a string or make a clone of it. See this answer for a more thougough explanation: Weird behavior with objects & console.log

Simon Paris
  • 399
  • 4
  • 7