Atlante Avila Atlante Avila - 6 months ago 25
Javascript Question

How to have a function wait until an object's value is not undefined js setTimeout

I need to stop a function from proceeding until my php script gets the contents from a file that takes a bit of time to load. Once loaded I update the object that holds this information on my JavaScript file:

var setData = seoApp.siteData.result.wordCount;


I have created a function that updates my html elements based on the results of the
wordCount
.

I want my script to continually check if the var
setData
is not undefined every few seconds to wait for the script to load the setData. I thought I could do this with setTimeout using this code:

for (var i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i);
if(setData !== undefined){
// stops the loop from running again
i = 11
//run if statements here.
}else {

}
}, 6000);
}


Well that didn't work. It waits a few seconds and then fires the for loop without waiting for six seconds until the next one.

What am I doing wrong and is this the best way to approach this?

As requested the php script to scrape the data:

<?php

$url = $_GET["url"];
$string = $_GET["keywords"];


libxml_use_internal_errors(true); //Prevents Warnings, remove if desired
$content = file_get_contents($url);
$explodedContent = explode("<title>", $content);
$explodedExplodedContent = explode("</title>", $explodedContent[1]);

$explodedBody = explode("<body>", $content);
$explodedExplodedBody = explode("</body>", $explodedBody[0]);

echo "{ \"result\": ". "{ ";
echo "\"titleCount\": " . substr_count($explodedExplodedContent[0], $string) . ", "; // title of that page.
echo "\"bodyCount\": " . substr_count(strip_tags($explodedExplodedBody[0]), $string);
echo " } }";
?>


Thanks in advance!

Answer

You probably already use the callback function of your XMLHttpRequest object, in which you set setData to the JSON output that the PHP script has returned. That is also the place where you should initiate any further processing:

xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        var setData = JSON.parse(xmlhttp.responseText);
        process(setData);
    }
};

// ...

function process(setData) {
    // Here you can do what you need to do with `setData`
}

If you want to do something while the data has not yet been returned, then use setInterval:

var myInterval = setInterval(function () {
     console.log('still waiting...');
}, 6000);

... and clear that interval once you have your data. But that you can easily do based on the request that returns (which is nicer than checking whether setData is not undefined):

function process(setData) {
    clearInterval(myInterval);
    // Here you can do what you need to do with `setData`
}

The reason your code did not work was that your for loop created 10 time-outs all at the same time, which all expired together 6 seconds later. It would have worked if you would have named the function given to setTimeout and passed that one to a new setTimeout when the first timeout expires:

setTimeout(function repeatTimeout() {
    console.log(i);
    if(setData !== undefined){
        // stops the loop from running again
        i =  11
        //run if statements here.
    } else {
        setTimeout(repeatTimeout, 6000);
    }
}, 6000);

... but with setInterval combined with clearInterval it is more straightforward.

Addendum

This fiddle has code based on the code you presented in a fiddle, with comments on where to make changes.