【问题标题】:Strange JavaScript Scope Error奇怪的 JavaScript 范围错误
【发布时间】:2017-04-11 01:14:40
【问题描述】:

所以在我的代码中的某个地方,我有一个函数可以比较当前时间和经过的时间(以毫秒为单位),并吐出一个人类可读的数字。因此,例如,如果您将 1491869404676 传递给此函数,它将将该数字与 JS 的 new Date().getTime() 函数进行比较,并输出可能为 20m。

现在,我有一段代码似乎在自己调用这个函数。我确信这是我不理解的某种范围问题。但是,如果您查看第二个控制台日志,它会正确返回以毫秒为单位的时间。一旦我将此对象推送到 momentArray(这是一个全局对象)中,它就会以某种方式调用我之前提到的函数并将其更改为人类可读的格式。为了您的方便,我已经评论了我正在谈论的内容。

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;
};

然后这个函数会返回这个初始化函数(部分代码省略):

        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;
}

这两个函数都存在于服务中。当这个函数返回到控制器时,控制器应该使用我之前提到的函数来转换那个奇怪的数字,以便很好地显示在视图上。

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;
        });
    };

有趣的是,如果我删除有关 core.timeElasped() 的部分,一切都会按预期工作。 getMomentsWithinRadius 服务中的 momentArray 日志一直显示一个长数字,并且不会自行自动转换。当然,如果我把这条线去掉,那么现在视图就会有这个疯狂的长数字,没人能理解。

我不知道为什么我的控制器代码似乎会影响服务上的某些全局变量。

感谢任何帮助。 谢谢!

编辑:

你的建议我试过了

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;
};

它仍然显示同样的问题。我创建了一个新的临时对象并将我想要的属性分配给它。我做错了吗?

【问题讨论】:

  • 创建一个能重现这个的 plunker 演示。我怀疑您的调试谜团的一部分与将对象记录到控制台不记录快照而是记录一个具有继承关系的活动对象有关,即使在记录之后对对象所做的任何更改仍将反映在控制台中。尝试记录字符串化版本,看看值是否更有意义......或改为设置断点
  • "我不知道为什么我的控制器代码似乎会影响服务上的某些全局变量。" - 呃,因为它确实会影响它就在那儿:vm.imageArray[0].time = …?请注意,所有这些变量都引用同一个数组:vm.imageArray == moments == momentArray == temp(甚至可能是== momentsInStates,因为您没有显示初始化它的位置)。它们都包含相同的对象,您正在改变其属性。
  • 当询问由您的代码引起的问题时,如果您提供人们可以用来重现问题的代码,您将获得更好的答案。见How to create a Minimal, Complete, and Verifiable example

标签: javascript angularjs scope


【解决方案1】:

避免延迟的反模式,并使用 Promise 的真正力量与 Promise.all 例如。您的第一个块中的代码只是

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
        }))
    ));
}

【讨论】:

  • 谢谢,等我搞清楚后我一定会实现的。我的代码实际上散布着这些延迟块,看起来很糟糕。
猜你喜欢
  • 2014-03-16
  • 1970-01-01
  • 2016-11-30
  • 2014-07-17
  • 1970-01-01
  • 2013-07-05
  • 2013-10-29
  • 2012-06-17
  • 1970-01-01
相关资源
最近更新 更多