【问题标题】:Promise function unable to access parent variablePromise 函数无法访问父变量
【发布时间】:2016-11-08 20:40:53
【问题描述】:

我不熟悉在 angularjs 中使用 Promise,目前在生成某些输出时遇到困难。我正在尝试使用 for 循环来生成句子数组,每个句子都按“levelName:groupName - description”进行。

我有一个名为“prodFactory”的工厂,它使用 $http.get 通过 getLevelNames()、getGroupNames(levelName) 和 getGroupData(groupName) 方法获取 levelName、groupName 和描述。从我的源文件中,我有一个包含 3 个 levelNames 的数组,每个 levelNames 都与一个包含 2 个 groupNames 的数组相关联。运行下面的代码时,我尝试记录值并得到以下结果:

i = 229, j = 2, data1 = 我定义的级别名称,data2 = 我定义的组名。

虽然我能够获得我的关卡和组名,但由于 i 和 j 的值与 for 循环定义的值不同,我得到了“未定义:未定义 - 描述”的结果。

有没有办法得到正确的输出?谢谢!

代码 sn-p

prodFactory.getLevelNames().then(function(data1){
            var suggestions = [];
            $scope.data1 = data1;
            for(i=0; i<data1.length; i++){
                prodFactory.getGroupNames(data1[i]).then(function(data2){
                    $scope.data2 = data2;
                    for(j=0; j<data2.length; j++){
                        prodFactory.getGroupData(data2[j]).then(function(data3){
                                $scope.data3 = data3;
                                for(k=0; k<data3[0].length; k++){
                                    console.log(i);
                                    console.log(j);
                                    console.log(data1);
                                    console.log(data2);
                                    suggestions.push($scope.data1[i]+": "
                                    +$scope.data2[j]+" - "+$scope.data3[0][k]);
                                };
                            });
                };
                });
        };
        $scope.getSuggestions = suggestions;
        console.log($scope.getSuggestions);
    });

【问题讨论】:

    标签: javascript angularjs closures


    【解决方案1】:

    你不能使用嵌套的 Promise

    因为执行顺序是不可预知的。

    【讨论】:

    • ES6 承诺语义被选择为具有确定性和可预测性。它们可能并非在所有情况下都很明显,但我认为这不是问题所在。
    【解决方案2】:

    我认为您对关闭有一些误解。所以也许你可以看看Closures。另外我建议你阅读IIFE

    我们总是可以尝试的一件事是简化问题。在这种情况下,我们可以先尝试两个层次的问题:我们只能先尝试 getLevelNames()、getGroupNames(levelName)。

    要解决两级问题,我可能会尝试:

    prodFactory.getLevelNames()
    .then(function(levelNames) {
        var suggestions = [];
        $scope.levelNames = levelNames;
        for(var i=0; i < levelNames.length; i++){ 
            // [IIFE][2]
            (function () {
                var index = i; 
                prodFactory.getGroupNames(levelNames[index])
                .then(function(groupNames) {
                    $scope.groupNames[index] = groupNames;
                    console.log(index);
                    for (var j = 0; j < groupNames.length; ++j) {
                        suggestions.push($scope.levelNames[index]+": "
                                    +$scope.groupNames[index][j]");
                    }
                });
            })();
        }
        $scope.getSuggestions = suggestions;
        console.log($scope.getSuggestions);
    });
    

    【讨论】:

      【解决方案3】:

      代码中的最后一个console.log 将在任何 HTTP 请求完成之前执行。那是因为 Promise 总是异步的。

      在循环中创建 Promise 会使以后处理结果变得更加困难。您将需要$q.all$q.spread 或一些Array 来添加结果。此外,发出大量 HTTP 请求将无法执行。您应该始终努力限制请求的数量。

      我建议为所有级别、组等创建返回结果的方法。

      prodFactory.getLevelNames().then(function(data1){
        prodFactory.getGroupNames(data1).then(function(data2){
          prodFactory.getGroupData(data2).then(function(data3){
            $scope.suggestions = makeSuggestions(data1, data2, data3)
            console.log($scope.suggestions);
          });
        });
      };
      

      请不要创建一个名为getSuggestions 的变量。看起来它是一个方法/函数而不是变量。

      【讨论】:

      • 我认为你误解了承诺。你应该尽量避免像回调一样嵌套它们。相反,如果它们是依赖的,则将它们展平然后链接。如果没有使用 $q.all。所以在这种情况下你可以做prodFactory.getLevelNames().then(prodFactory.getGroupNames).then(prodFactory.getGroupData).then(data2 =&gt; console.log(data2);
      • @ste2425 你的解决方案更好,但不需要压平链条,所以我跳过了那部分。
      猜你喜欢
      • 2015-11-03
      • 1970-01-01
      • 1970-01-01
      • 2019-01-05
      • 2022-01-10
      • 1970-01-01
      • 1970-01-01
      • 2018-06-23
      • 1970-01-01
      相关资源
      最近更新 更多