-3

So somewhere in my code I have a function that compares the current time and the time elapsed in miliseconds and spits out a human readable number. So for example, if you pass in 1491869404676 into this function it will compare that number to the JS new Date().getTime() function and spit out maybe 20m.

Now, I have a piece of code that is seemingly calling this function by itself. I am convinced this is a scope issue of some sort that I do not understand. But if you look at the second console log it returns the time in miliseconds correctly. As soon as I push this object into momentArray (Which is a global) it somehow calls the function I mentioned previously and changes it into a human readable format. I have commented the lines I am talking about for your convenience.

function getMomentsWithinRadius(momentsInStates) {
    var deferred = $q.defer();
    for(var i = 0; i < momentsInStates.length; i++) {
        (function(i) {
            awsServices.getMomentMetaData(momentsInStates[i].Key).then(function(metaData) {
                console.log("GET MOMENTS META DATA")
                console.log(metaData.time); //Returns 1491869404676
                momentArray.push({ 
                    key: constants.IMAGE_URL + momentsInStates[i].Key, 
                    description: metaData.description,
                    likes: metaData.likes,
                    location: metaData.location,
                    time: 1491869404676, //<-- Simplified to make a point, should be metaData.time
                    uuids: metaData.uuids,
                    views: metaData.views
                });
                console.log(momentArray); //Time field should be 1491869404676 but I get 20m
                if(momentArray.length === momentsInStates.length) {
                    var temp = momentArray; //<-- My attempt to mess with the scope
                    deferred.resolve(temp);
                }
            }, function(error) {
                console.log("ERROR - momentService.getMomentsWithinRadius");
                console.log(error);
            });
        })(i);
    }
    if(momentsInStates.length === 0) {
        deferred.resolve(momentsInStates);
    }
    return deferred.promise;
};

This function will then return to this initialization function(some code ommitted):

        getMomentsWithinRadius(momentsInStates).then(function(moments) {
            console.log("GET MOMENTS WITHIN RADIUS");
            console.log(moments);
            momentArray = moments;
            $ionicLoading.hide().then(function() {
                deferred.resolve(moments);      
            });
return deferred.promise;
}

Both these functions lives in the service. When this function returns to the controller, the controller should use the function I mentioned before to convert that strange number to display on the view nicely.

function updateView() {
        momentsService.initializeView()
        .then(function(moments){
            console.log("INITIALIZE VIEW");
            console.log(moments);
            if(moments.length > 0) {
                vm.imageArray = updateObject(moments);
                vm.imageArray[0].time = core.timeElapsed(vm.imageArray[0].time); //<-- If I remove this line everything works perfectly.
            }
            else {
                vm.imageArray = undefined;
            }
        }, function(error) {
            vm.currentImage = undefined;
        });
    };

The interesting part is if I remove the bit about core.timeElasped() everything works as expected. The momentArray log alllll the way in getMomentsWithinRadius service displays a long number as it should and doesn't automatically convert it by itself. Of course, if I take that line out the view has this crazy long number now that nobody understands.

I have no idea why my controller code is seemingly affecting some global variable on the service.

Any help is appreciated. Thanks!

EDIT:

With your suggestions I tried

function getMomentsWithinRadius(momentsInStates) {
    var deferred = $q.defer();
    var temp = [];
    for(var i = 0; i < momentsInStates.length; i++) {
        (function(i) {
            awsServices.getMomentMetaData(momentsInStates[i].Key).then(function(metaData) {
                console.log("GET MOMENTS META DATA")
                console.log(metaData);
                temp.push({ 
                    key: constants.IMAGE_URL + momentsInStates[i].Key, 
                    description: metaData.description,
                    likes: metaData.likes,
                    location: metaData.location,
                    time: metaData.time,
                    uuids: metaData.uuids,
                    views: metaData.views
                });
            console.log(temp);
            if(temp.length === momentsInStates.length) {
                momentArray = temp;
                deferred.resolve(temp);
            }
        }, function(error) {
            console.log("ERROR - momentService.getMomentsWithinRadius");
            console.log(error);
        });
        })(i);
    }
    if(momentsInStates.length === 0) {
        deferred.resolve(momentsInStates);
    }
    return deferred.promise;
};

It still showing the same problem. I created a new temp object and assigned the properties I wanted onto it. Did I do this incorrectly?

MatTaNg
  • 923
  • 8
  • 23
  • 41
  • Avoid the [deferred antipattern](http://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Apr 11 '17 at 01:33
  • Create a plunker demo that reproduces this. I suspect part of your debugging mystery relates to the fact that logging objects to console does not log a snapshot but rather a live object that has inheritance and any changes made to object even after logging it will still be reflected in console. Try logging stringified versions instead and see if values make more sense...or set breakpoints instead – charlietfl Apr 11 '17 at 01:33
  • 1
    "*I have no idea why my controller code is seemingly affecting some global variable on the service.*" - uh, because it **does** affect it right there: `vm.imageArray[0].time = …`? Notice that all those variable refer to the same array: `vm.imageArray == moments == momentArray == temp` (and maybe even `== momentsInStates`, as you haven't show where you initialise that). They all contain the same object, whose property you are mutating. – Bergi Apr 11 '17 at 01:39
  • And yes, [don't get confused by `console.log`](http://stackoverflow.com/a/23392650/1048572) – Bergi Apr 11 '17 at 01:43
  • When asking a question about a problem caused by your code, you will get much better answers if you provide code people can use to reproduce the problem. See [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). – georgeawg Apr 11 '17 at 08:43

1 Answers1

0

Avoid deferred antipattern, and use the true power of Promises with Promise.all for example. The code in your first block is just

function getMomentsWithinRadius(momentsInStates) {
    return Promise.all(momentsInStates.map(moment =>
        awsServices.getMomentMetaData(moment.Key).then(metaData => ({
            key: constants.IMAGE_URL + moment.Key, 
            description: metaData.description,
            likes: metaData.likes,
            location: metaData.location,
            time: metaData.time,
            uuids: metaData.uuids,
            views: metaData.views
        }))
    ));
}
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
  • Thanks, I'll be sure to implement this after I figure this out. My code is literally scattered with these deferred blocks and it looks awful. – MatTaNg Apr 11 '17 at 03:48