AngularJS范围和延迟

AngularJS范围和延迟,angularjs,angularjs-directive,promise,angularjs-scope,Angularjs,Angularjs Directive,Promise,Angularjs Scope,我有一个服务,做了一些艰难的事情,并回报一个承诺: .factory('myService', function($q) { return { doSomethingHard: function() { var deferred = $q.defer(); setTimeout(function() { deferred.resolve("I'm done!");

我有一个服务,做了一些艰难的事情,并回报一个承诺:

.factory('myService', function($q) {

    return {
        doSomethingHard: function() {
            var deferred = $q.defer();

            setTimeout(function() {
                deferred.resolve("I'm done!");
            }, 1000);

            return deferred.promise;
        }
    };
})
我有一个控制器,它使用该服务向作用域添加一个函数:

.controller('MyCtrl', function($scope, myService) {

    $scope.doSomething = function() {
        var promise = myService.doSomethingHard();

        promise.then(function(result) {
            alert(result);
        });
    };

})
我使用指令通过解析属性来调用该控制器函数:

.directive('myDirective', function($parse) {
    return {
        link: function(scope, el, attr) {

            var myParsedFunction = $parse(attr.myDirective);

            el.bind('click', function() {
                myParsedFunction(scope);
            });
        }
    };
})
使用模板

<div ng-controller="MyCtrl">
    <button my-directive="doSomething()">The Button</button>
</div>

按钮
单击该按钮将触发事件侦听器,它调用控制器函数
doSomething
,调用服务函数
doSomethingHard
,该函数返回一个承诺,,该承诺永远不会解决

整件事都摆在这里:

有什么好处

谢谢

编辑:多亏了Maksym H,它看起来像是将承诺解析包装在
$scope中。$apply()
使其在控制器中启动。我有一把小提琴正在演奏。但我真的不想让这个范围出现在我的服务中


我也很想知道为什么会这样。或者更好的是,为什么它在包装在一个作用域apply中时没有解析承诺就不能工作。当考虑属性时,整个角度世界与常规Javascript世界的类比是有意义的,因为需要消化更改,但这是一个承诺。。。使用回调函数。$q是否只是将承诺标记为已解决,并等待作用域消化该属性更新并触发其已解决的处理程序函数

还有另一种方法:尝试在指令中定义作用域,并将此属性绑定到父作用域

.directive('myDirective', function() {
  return {
    scope: { myDirective: "=" }, // or { myParsedFunction: "=myDirective" },
    link: function(scope, el, attr) {

        el.bind('click', function() {
            scope.myDirecive(scope); // or scope.myParsedFunction(scope)
        });
    }
  };
})
但最主要的是在一段时间后解析时运行摘要:

.factory('myService', function($q, $timeout) {

    return {
        doSomethingHard: function() {
            alert('3. doing something hard');

            var deferred = $q.defer();

            // using $timeout as it's working better with promises
            $timeout(function() {
                alert('4. resolving deferred');
                deferred.resolve('Hello World!'); // Here...
            }, 1000);

            return deferred.promise;
        }
    };
})

另外,请确保您将方法作为父范围的模型传递,而不是通过HTML中的“()”应用此方法


按钮

只需将
设置超时
替换为
$timeout
(记住将
$timeout
注入您的服务中)。这是一个。

@nicholas,我已经更新了Plunker的密码。我希望它对你有用。回答得真棒。谢谢我已经按照您的建议,通过向服务中添加$rootScope实现了这一点。谢谢但我仍然对这个解决方案不太满意,也不理解(见我的编辑)。@nicholas,你不必担心,因为这是本机设置超时的错。使用此选项后,agnular似乎不再关注解析。在实际示例中,您可能会使用XHR erquest和resolve on success之类的工具,对吗?但是现在您可以使用angular的$timeout提供程序来测试它,该提供程序在angular承诺中工作得更好。此外,您还可以尝试使用XHR请求进行解析,它应该可以正常工作。这里是更新的提琴()啊。这是有道理的。解析一个属性,这样我就不必为该指令创建一个孤立的作用域,这也很有效。在我的生产代码中,除了使用$http而不是$timeout之外,其他代码都是相同的,我仍然必须编写
$scope.$apply(fn)
,而不仅仅是
fn()
,这有点奇怪,但问题一定来自其他地方。为了我自己的教育,我会试着复制一把小提琴,但现在它起作用了,这对我来说已经足够好了。谢谢。即使承诺没有解决,这个返回不是在1秒后完成吗?