7

I have this interval, that does an ajax request, currently every 5 seconds. I am having an issue with the if statement. my code ALWAYS enters it, and the two json values are the exact same, why is it seeing them as different?

var newActivity = null, oldActivity = null;
setInterval(function(){
    $.ajax({
        type: "get",
        url: "/get/new_activity",
        dataType: "json",
        success: function(data){
            oldActivity = newActivity;
            newActivity = data;
            console.log(JSON.stringify(oldActivity));
            console.log(JSON.stringify(newActivity));
            if(JSON.stringify(oldActivity) != JSON.stringify(newActivity)){
                $("#new-activity").slideDown( "fast" );
            }
        }
    });
}, 5000);

Edit
Here is the console output (dashed line is to separate requests, it isn't in the actual output)

null
[{"title":"How many planets are in the solar system?","title_url":"How-many-planets-are-in-the-solar-system%3F","id":"2","answers":"1","asked":"2013-01-11 10:03:50","asked_pretty":"Today","activity":"2013-01-11 12:33:53","activity_pretty":"Today"},{"title":"Why is the sky blue?","title_url":"Why-is-the-sky-blue%3F","id":"1","answers":"1","asked":"2013-01-11 09:55:13","asked_pretty":"Today","activity":"2013-01-11 12:03:45","activity_pretty":"Today"}]

---------------------------------------------------

[{"title":"How many planets are in the solar system?","title_url":"How-many-planets-are-in-the-solar-system%3F","id":"2","answers":"1","asked":"2013-01-11 10:03:50","asked_pretty":"Today","activity":"2013-01-11 12:33:53","activity_pretty":"Today"},{"title":"Why is the sky blue?","title_url":"Why-is-the-sky-blue%3F","id":"1","answers":"1","asked":"2013-01-11 09:55:13","asked_pretty":"Today","activity":"2013-01-11 12:03:45","activity_pretty":"Today"}]
[{"title":"How many planets are in the solar system?","title_url":"How-many-planets-are-in-the-solar-system%3F","id":"2","answers":"1","asked":"2013-01-11 10:03:50","asked_pretty":"Today","activity":"2013-01-11 12:33:53","activity_pretty":"Today"},{"title":"Why is the sky blue?","title_url":"Why-is-the-sky-blue%3F","id":"1","answers":"1","asked":"2013-01-11 09:55:13","asked_pretty":"Today","activity":"2013-01-11 12:03:45","activity_pretty":"Today"}]

---------------------------------------------------

[{"title":"How many planets are in the solar system?","title_url":"How-many-planets-are-in-the-solar-system%3F","id":"2","answers":"1","asked":"2013-01-11 10:03:50","asked_pretty":"Today","activity":"2013-01-11 12:33:53","activity_pretty":"Today"},{"title":"Why is the sky blue?","title_url":"Why-is-the-sky-blue%3F","id":"1","answers":"1","asked":"2013-01-11 09:55:13","asked_pretty":"Today","activity":"2013-01-11 12:03:45","activity_pretty":"Today"}]
[{"title":"How many planets are in the solar system?","title_url":"How-many-planets-are-in-the-solar-system%3F","id":"2","answers":"1","asked":"2013-01-11 10:03:50","asked_pretty":"Today","activity":"2013-01-11 12:33:53","activity_pretty":"Today"},{"title":"Why is the sky blue?","title_url":"Why-is-the-sky-blue%3F","id":"1","answers":"1","asked":"2013-01-11 09:55:13","asked_pretty":"Today","activity":"2013-01-11 12:03:45","activity_pretty":"Today"}]
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338
  • Please post the output of `JSON.stringify(oldActivity)` and `JSON.stringify(newActivity)` when you say the are the same but still go into the loop. – Ruan Mendes Jan 11 '13 at 21:15
  • 1
    Please post the *actual values* resulting from the JSON stringification of `newActivity` and `oldActivity`. If they contain *objects* then there is *no guarantee of ordering or equality in JSON form*. (The are other encodings that are equivalent but not identical; they are less common.) –  Jan 11 '13 at 21:21
  • It seems hard to debug properly with an interval of 5 seconds. Does that happen with just two calls ? – Denys Séguret Jan 11 '13 at 21:22
  • Are you sure the properties are in the same order each time? Maybe they aren't? – gen_Eric Jan 11 '13 at 21:25
  • Are you *sure* it "always enters [the conditional]"? Unless there is a "sneaky character" (e.g. not-quite-space that was lost in copy'n'paste) the data should have only been "!=" the first time. –  Jan 11 '13 at 21:27
  • The two strings you posted are equal, see http://jsfiddle.net/GMs8P/ – Ruan Mendes Jan 11 '13 at 21:27
  • 1
    @Christophe Except it was *not correct* at all, given with the first output listing. –  Jan 11 '13 at 21:27
  • 1
    @Christophe pst is correct, I deleted my answer because it was wrong. – bfavaretto Jan 11 '13 at 21:29
  • 2
    @Christophe: The fact that his code says they are different. – gen_Eric Jan 11 '13 at 21:35
  • @RyanNaddy Did you try my recursive equality test? If it doesn't work, could be something to do with invisible characters in your strings? – Ruan Mendes Jan 11 '13 at 21:40
  • 2
    I am an idiot. I reset `newActivity` to `null` in a different function. That is why they were coming back as not equal every time. – Get Off My Lawn Jan 11 '13 at 21:41
  • @Christophe the OP's code is fine, `oldActivity = newActivity; newActivity = data;` does not mean `oldActivity = newActivity = data` http://jsfiddle.net/HdJeD/ – Ruan Mendes Jan 11 '13 at 21:41
  • @RyanNaddy the joy of coding with globals, but you still shouldn't rely on `JSON.stringify` for equality testing – Ruan Mendes Jan 11 '13 at 21:44
  • @JuanMendes your right I shouldn't rely on it, but for what this task doesn't it isn't really important if it is off some. It just says "Hey there are some updates click me to load them" type of thing. – Get Off My Lawn Jan 11 '13 at 21:48
  • @Christophe It doesn't matter http://jsfiddle.net/HdJeD/1/ You should test stuff before you make suggestions – Ruan Mendes Jan 11 '13 at 21:51
  • @JuanMendes ouch, my mistake! (and no test needed really, just time to wake up...). Point taken, I have deleted my misleading comments. – Christophe Jan 11 '13 at 22:10
  • 1
    @Christophe I'm sorry if my answer confused you. It was a lapse, I thought I had an Eureka moment, but I was actually suggesting something that (a) is impossible in js; (b) was untested, and (c) ignored that the code said `!=`, not `==`. So I deleted it. Given the OP's final statement, I suggest we close this as too localized, and forget it. – bfavaretto Jan 11 '13 at 22:13
  • @RyanNaddy you'll be spamming people with unnecessary updates when you run into this problem. No reason to use something that is known to be unreliable, I showed you something better already. Don't be careless with your code, just because "it isn't really important", it's the mark of a great developer. – Ruan Mendes Jan 12 '13 at 01:02

3 Answers3

10

JSON objects are not guaranteed to be serialized the same way, properties are not guaranteed to be in the same order, using JSON.stringify is not a good way to test object equality.

A better example is a function like (found on the internet a while ago, wish I could give credit to the original author)

/**
 * Deep compare of two objects.
 *
 * Note that this does not detect cyclical objects as it should.
 * Need to implement that when this is used in a more general case. It's currently only used
 * in a place that guarantees no cyclical structures.
 *
 * @param {*} x
 * @param {*} y
 * @return {Boolean} Whether the two objects are equivalent, that is,
 *         every property in x is equal to every property in y recursively. Primitives
 *         must be strictly equal, that is "1" and 1, null an undefined and similar objects
 *         are considered different
 */
function equals ( x, y ) {
    // If both x and y are null or undefined and exactly the same
    if ( x === y ) {
        return true;
    }

    // If they are not strictly equal, they both need to be Objects
    if ( ! ( x instanceof Object ) || ! ( y instanceof Object ) ) {
        return false;
    }

    // They must have the exact same prototype chain, the closest we can do is
    // test the constructor.
    if ( x.constructor !== y.constructor ) {
        return false;
    }

    for ( var p in x ) {
        // Inherited properties were tested using x.constructor === y.constructor
        if ( x.hasOwnProperty( p ) ) {
            // Allows comparing x[ p ] and y[ p ] when set to undefined
            if ( ! y.hasOwnProperty( p ) ) {
                return false;
            }

            // If they have the same strict value or identity then they are equal
            if ( x[ p ] === y[ p ] ) {
                continue;
            }

            // Numbers, Strings, Functions, Booleans must be strictly equal
            if ( typeof( x[ p ] ) !== "object" ) {
                return false;
            }

            // Objects and Arrays must be tested recursively
            if ( !equals( x[ p ],  y[ p ] ) ) {
                return false;
            }
        }
    }

    for ( p in y ) {
        // allows x[ p ] to be set to undefined
        if ( y.hasOwnProperty( p ) && ! x.hasOwnProperty( p ) ) {
            return false;
        }
    }
    return true;
},
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • I wrote a simpler solution but with the same idea in this answer: http://stackoverflow.com/a/33378418/3060087 – Price Oct 27 '15 at 21:04
0

One solution would be to read the json data as text instead of json, and on success you check if the response string from the server differs from the last response string. Then you can call JSON.parse on the string. But this makes the comparison much easier and should only need a slight modification of your code.

Strille
  • 5,741
  • 2
  • 26
  • 40
  • 1
    But dataType is set to "json", which means data is an object in your case, which makes comparison difficult. My suggestion is to set dataType to "text", and then skip JSON.stringify when comparing. – Strille Jan 11 '13 at 21:36
-2

I think you should try comparing their properties.


for(var property in JSON.stringify(oldActivity))
    {
      if(JSON.stringify(oldActivity)[property]!=JSON.stringify(newActivity)[property])
                   $("#new-activity").slideDown( "fast" );
    }
    
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
TaLha Khan
  • 2,413
  • 2
  • 25
  • 39
  • 3
    If you're going to be comparing properties, lose the `JSON.stringify`. – gen_Eric Jan 11 '13 at 21:18
  • 2
    You're only pushing the stringify problem down one level, a recursive function is required, or you'll have to implement custom testing for each level of every JSON structure you ever compare – Ruan Mendes Jan 11 '13 at 21:31