15

注意:小提琴使用旧版本的 Angular,它不再工作,因为从 1.2 开始,Angular 模板引擎不能透明地处理 Promise。

我正在研究链接承诺以填充我的范围,然后让范围自动更新 dom。

不过,我遇到了问题。如果我在已经解决的承诺上调用“then”,它会创建一个新的承诺(它将异步但几乎立即调用成功函数)。我认为问题在于,在调用成功函数时我们已经离开了摘要循环,因此 dom 永远不会更新。

这是代码:

<div ng-controller="MyCtrl">
    Hello, {{name}}! <br/>
    {{name2}}<br/>
    <button ng-click="go()">Clickme</button><br/>
    {{name3}}
</div>

var myApp = angular.module('myApp',[]);

function MyCtrl($scope, $q) {
    var data = $q.defer();    
    setTimeout(function() {$scope.$apply(data.resolve("Some Data"))}, 2000);
    var p = data.promise;

    $scope.name = p.then(angular.uppercase);
    $scope.name2 = p.then(function(x) { return "Hi "+x;});
    $scope.go = function() {
            $scope.name3 = p.then(function(x) { 
                // uncomment this to make it work:
                //$scope.$apply();
                return "Finally: "+x;
            });
    };
 }

http://jsfiddle.net/QZM4d/

是否有某种方法可以使这项工作在每次我链承诺时都调用 $apply ?

4

1 回答 1

15

注意:小提琴使用旧版本的 Angular,它不再工作,因为从 1.2 开始,Angular 模板引擎不能透明地处理 Promise。

引用@pkozlowski.opensource :

在 AngularJS 中,promise 解析的结果是在 $digest 循环内异步传播的。因此,使用 then() 注册的回调只会在进入 $digest 循环时被调用。

因此,当单击按钮时,我们处于摘要循环中。then() 创建一个新的 Promise,但 then() 的结果将不会传播到下一个摘要周期,该周期永远不会到来(因为没有 $timeout 或 $http 或 DOM 事件来触发)。如果您使用 ng-click 添加另一个不执行任何操作的按钮,然后单击该按钮,它将导致摘要循环,您将看到结果:

<button ng-click="">Force digest by clicking me</button><br/>

这是一个这样做的小提琴

小提琴还使用 $timeout 而不是 setTimeout - 然后 $apply() 不需要。

希望您清楚何时需要使用 $apply。有时您确实需要手动调用它。

于 2013-02-02T02:23:56.570 回答