2

I'm discovering the concept of "objects" in JavaScript. I'm making an RSS Parser, and I have an error (commented).

function MyParser (feed_url) {  // Construct
    "use strict";
    this.feedUrl = feed_url;
    this.pubArray = [];

    if (typeof (this.init_ok) == 'undefined') {
        MyParser.prototype.parse = function () {
        "use strict";
        var thisObj = this;
        $.get(this.feedUrl, function (data, textStatus, jqXHR) {
            if (textStatus == 'success') {
                var xml = jqXHR.responseXML,
                    //lastBuildDate = new Date($(xml).find('lastBuildDate').text());
                    items = $(xml).find('item');
                items.each(function () {
                    var pubSingle = thisObj.makeObj($(this).find('pubDate').text(),
                                                    $(this).find('link').text(),
                                                    $(this).find('title').text(),
                                                    $(this).find('description').text(),
                                                    $(this).find('encoded').text(),
                                                    $(this).find('commentRss').text(),
                                                    $(this).find('comments').last().text());
                    thisObj.pubArray.push(pubSingle);
                });
                console.log(thisObj.pubArray); // OK
            }
        }, 'xml');
        console.log(this.pubArray); // Empty
        return (this.pubArray);
    };

    MyParser.prototype.makeObj = function (pubDate, pubLink, pubTitle, pubDesc, pubContent, pubComCount, pubComLink) {
        "use strict";
        var pubSingle = {};
        pubSingle.pubDate = new Date(pubDate);
        pubSingle.pubLink = pubLink;
        pubSingle.pubTitle = pubTitle;
        pubSingle.pubDesc = pubDesc;
        pubSingle.pubContent = pubContent;
        pubSingle.pubComCount = pubComCount;
        pubSingle.pubComLink = pubComLink;
        return (pubSingle);
    };
}
this.init_ok = true;
}

If you look at the console.log(), you'll see that the line // OK is outputting my array correctly.

But later, when returning from $.get, my array is empty.

Does anybody have an idea why, and how to correct that please?

JackDev
  • 4,891
  • 1
  • 39
  • 48
Max13
  • 919
  • 2
  • 9
  • 27
  • That has nothing to do with objects or scope, but with the asynchronicity of Ajax calls. – Felix Kling Dec 16 '11 at 12:22
  • 1
    possible duplicate of [JavaScript asynchronous return value / assignment with jQuery](http://stackoverflow.com/questions/7779697/javascript-asynchronous-return-value-assignment-with-jquery) – Felix Kling Dec 16 '11 at 12:23

3 Answers3

4

This is not a problem with variable-scope. The problem here is that you're working with asynchronous flow and you're not thinking correctly the flow.

Let me explain:

When you do your .get, you fire a parallel asynchronous process that will request information from the browser, but your main program's flow keeps going, so when you get to your "return" statement, your array has not been filled yet with the response from your get method.

You should use your array from inside the get callback and not outside of it, since you can't guarantee that the array will have the information you need.

Does it make any sense?

Let me know!

Further explanation

According to your comments, you're still doing something like this:

var results = MyParser(feed_url); //code that uses results.pubArray

And you cannot do that. Even though you're setting your "pubArray" inside your .get callback, you're trying to use pubArray right after you called MyParser and that's before the .get callback is called. What you have to do, is call your next step on your program's logic from within the .get callback... that's the only way you can be sure that the pubArray is filled with proper data.

I hope that makes it clearer.

Deleteman
  • 8,500
  • 6
  • 25
  • 39
  • Hey, thanks, I understand. But... How to "return" the values ? Only by returning them IN the $.get ? – Max13 Dec 16 '11 at 16:54
  • You can't return the value from your method, you'd have to, for instance, trigger another method on the `.get` callback passing it the return value as a parameter. – Deleteman Dec 16 '11 at 18:18
  • Sorry but... I do what I want to do on the callback. Then I call one of my prototype.method(), I send my array as argument, and this method will set the object attribute (array) with its argument? I wonder if the callback won't call the method from another object (created because the callback will be called within the $.get context). I don't know yet, but I hope there is nothing like that :/ --- – Max13 Dec 17 '11 at 00:16
  • I've just tried it. I've created a method in my object, setPubArray(); `thisObj.setPubArray(thisObj.pubArray); console.log(thisObj.pubArray); // Ok` But going out of the $.get, and still empty... :( – Max13 Dec 17 '11 at 00:24
  • Added an edit to my original answer, hopefully that clears it up a bit :) – Deleteman Dec 18 '11 at 02:44
  • Aha. Yeah ok. I've understood few minutes before your edit. Actually, I found how to bypass this "restriction" (do everything inside the get callback). I answer this post. – Max13 Dec 19 '11 at 10:49
3

This is because your line

 console.log(this.pubArray); // Empty

is being called directly after you issue your Ajax request; it hasn't had time to fetch the data yet. The line

console.log(thisObj.pubArray); // OK

is being called inside the Ajax callback, by which time the data has been fetched.

Graham
  • 6,484
  • 2
  • 35
  • 39
0

Thank you all, and particulary @Deleteman .

Here is what I did:

$.get(this.feedUrl, 'xml').success(function () {
    thisObj.handleAjax(arguments[0], arguments[1], arguments[2]);
    $(document).trigger('MyParserDone');
}).error(function () {
    $(document).trigger('MyParserFailed');
});

Then, when i enter "HandleAjax", i'm back in my object context, so "this" refers to my object and the right properties. The only "problem" is that I have to set a listener (MyParserDone) to make sure the parsing is finished.

Max13
  • 919
  • 2
  • 9
  • 27