-2

I have a rather large script that will be executed from the console while on a specific page --

It basically has 3 parts

1) ajax request to grab HTML from another page then create array from desired data pulled out of the HTML

2) scan current page for all words, ignoring words from step 1, create array with all words that werent ignored

3)not there yet but will be simple after I get this question figured out

When I run it once from the console I get:

Uncaught TypeError: Cannot read property 'length' of undefined(…)

If I hit up arrow then enter and run the script a second time, it goes through step 1 and 2 perfectly like I want.

Is this due to the ajax request not being finished when step 2 asks for the array?

var myFilter;
var dynamicExclude;
var arrDynamicExclude;
var staticExclude = ['are', 'is', 'where', 'was'];
var mergedExclude;
var words;
var word;
var ignore;
var finalList;

var stepOne = function () {
    //.unique
    Array.prototype.unique = function () {
        var a = this.concat();
        for (var i=0; i<a.length; ++i) {
            for(var j=i+1; j<a.length; ++j) {
                if(a[i] === a[j])
                    a.splice(j--, 1);
            }
        }
        return a;
    };
    // request HTML from wikipedia most common words
    $.ajax({
        url: 'https://en.wikipedia.org/wiki/Most_common_words_in_English',
        type: 'GET',
        dataType: 'html',
        success: function(data) {
                dynamicExclude = $.map($(data).find('.wikitable tr'), function(el, index) {
                return $(el).find('td:last').text() || null;
            });
            mergedExclude = dynamicExclude.concat(staticExclude).unique();
        }
    });
//->
    console.log("step 1");
}

var stepTwo = function () {
    // modified from: http://iamnotagoodartist.com/web/quick-and-dirty-word-frequency-analysis-with-javascript/
   var words = (function(){
        var sWords = document.body.innerText.toLowerCase().trim().replace(/[,;.]/g,'').split(/[\s\/]+/g).sort();
        // count w/ duplicates
        var iWordsCount = sWords.length;
        // array of words to ignore
        var ignore = mergedExclude;
        var ignore = (function(){
            // object prop checking > in array checking
            var o = {};
            var iCount = ignore.length;
            for (var i=0;i<iCount;i++){
                o[ignore[i]] = true;
            }
            return o;
        }());
        //do not allow words that are 1 chracter or non-alpha characters
        function myValidate(word) {
            return (word.length === 1 || /[^A-Z]/i.test(word)) ? true : false;
        }
        // object for math
        var counts ={};
        for (var i=0; i<iWordsCount; i++) {
            var sWord = sWords[i];
            if (!ignore[sWord] && !myValidate(sWord)) {
                counts[sWord] = counts[sWord] || 0;
                counts[sWord]++;
            }
        }
        // an array of objects to return
        var arr = [];
        for (sWord in counts) {
            arr.push({
                text: sWord,
                frequency: counts[sWord]
            });
        }
        // sort array by descending frequency | http://stackoverflow.com/a/8837505
        return arr.sort(function(a,b){
            return (a.frequency > b.frequency) ? -1 : ((a.frequency < b.frequency) ? 1 : 0);
        });
    }());
    (function(){
        // count w/o duplicates
        var iWordsCount = words.length;
        for (var i=0; i<iWordsCount; i++) {
            var word = words[i];
            //console.log(word.frequency, word.text);
        }
    }());
    var finalList =[];
    finalList = words.slice(0, 25);
    console.log(JSON.stringify(finalList));
//->
        console.log("step 2");
}

var stepThree = function(){
//->
        console.log("step 3");
}
//put the steps into the run queue
var runQueue = [stepOne,stepTwo,stepThree];
//run through the steps, removing the step from the queue after running
while (runQueue.length){
    runQueue.shift().call();
}
ZiNG
  • 89
  • 1
  • 13

1 Answers1

0

The issue is with the following line of code:

 $.ajax({
        url: 'https://en.wikipedia.org/wiki/Most_common_words_in_English',
        type: 'GET',
        dataType: 'html',
        success: function(data) {
                dynamicExclude = $.map($(data).find('.wikitable tr'), function(el, index) {
                return $(el).find('td:last').text() || null;
            });
         HERE   mergedExclude = dynamicExclude.concat(staticExclude).unique();
        }
    });

you no longer have access to dynamicExclude outside of the success function. And hence the

Uncaught TypeError: Cannot read property 'length' of undefined(…)

I cut that one line and it went through and logged the stuff from step 1.

Picture as proof: all I did was remove that line...

enter image description here

omarjmh
  • 13,632
  • 6
  • 34
  • 42
  • Did not work, I am setting mergedExclude to include both dynamicExclude and staticExclude while in the success function, so I can use it outside of the success function is this incorrect? – ZiNG Apr 16 '16 at 00:27
  • 1
    Why doesn't he have access to them? Looks like he is declaring both mergedExclude and dynamicExclude as global variables. In fact it looks like he has declared just about everything as a global variable. I think it's more likely an async issue – David784 Apr 16 '16 at 00:28
  • have to refresh the page between runs, it works fine on the 2nd run. – ZiNG Apr 16 '16 at 00:28
  • 2
    its because when he gets the data it is asynchronous, it comes back AFTER he sets it so when it gets to that part of the code, its still just the variable he set up at the top, which is undefined, if he set that variable to and empty array, this error doesnt happen, but it still wont do what he wants – omarjmh Apr 16 '16 at 00:30