在$ Q服务是angularjs非常强大,使我们的生活与异步代码更容易。
我对angular并不陌生,但是对我而言,使用延迟API并不是一个新手。我必须说,我完全同意How to use文档的部分内容+在文档中有非常有用的链接+我也检查了源代码。
How to use
我的问题是更多的 引擎盖下* 的角推迟和承诺API对象的部分。它们 生命周期 中的确切 阶段 是什么,以及它们如何相互作用。我的假设是,当诺言解决时,它会调用摘要循环?是/否? *rootScope.Scope
rootScope.Scope
能否针对以下方面提供详细的答案:
我将不胜感激并接受最详细的答案,并尽可能多地引用文档或源代码(我自己找不到)。我以前找不到与该主题相关的任何讨论(如果已有的话)-请发布链接。
ps:对于建议为该问题提供更好标题的人,可以+1,请在评论中添加您的建议。
干杯!
承诺有三个状态
.then
throw
在Angular中,promise异步解析,并通过解决via $rootScope.$evalAsync(callback);(从此处获取)来提供其保证。
$rootScope.$evalAsync(callback);
由于它是通过运行的,因此$evalAsync我们知道在诺言解决之后(正常情况下)至少会发生一个摘要周期,因为如果没有进行摘要,它将安排新的摘要。
$evalAsync
这也是为什么例如当您要在Angular中对Promise 代码进行单元测试时,由于$ evalAsync执行是摘要循环的一部分,因此需要运行摘要循环(通常在rootScopevia上$rootScope.digest())。
rootScope
$rootScope.digest()
注意: 这显示了来自Angular 1.2的代码路径,Angular 1.x中的代码路径都相似,但在1.3+版本中,$ q已重构为使用原型继承,因此该答案在代码中不准确(但实际上)。这些版本。
1)创建$ q时,它会执行以下操作:
this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) { return qFactory(function(callback) { $rootScope.$evalAsync(callback); }, $exceptionHandler); }];
依次执行以下操作:
function qFactory(nextTick, exceptionHandler) {
并且仅将解析nextTick通过作为$evalAsync内部解析并通知:
nextTick
resolve: function(val) { if (pending) { var callbacks = pending; pending = undefined; value = ref(val); if (callbacks.length) { nextTick(function() { var callback; for (var i = 0, ii = callbacks.length; i < ii; i++) { callback = callbacks[i]; value.then(callback[0], callback[1], callback[2]); } }); } } },
在根作用域上,$ evalAsync定义为:
$evalAsync: function(expr) { // if we are outside of an $digest loop and this is the first time we are scheduling async // task also schedule async auto-flush if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) { $browser.defer(function() { if ($rootScope.$$asyncQueue.length) { $rootScope.$digest(); } }); } this.$$asyncQueue.push({scope: this, expression: expr}); }, $$postDigest : function(fn) { this.$$postDigestQueue.push(fn); },
如您所见,如果我们不在其中,并且以前未计划过摘要,那么您确实在计划摘要。然后将功能推到$$asyncQueue。
$$asyncQueue
反过来在$ digest内部(在一个循环中以及 在 测试观察者 之前 ):
asyncQueue = this.$$asyncQueue, ... while(asyncQueue.length) { try { asyncTask = asyncQueue.shift(); asyncTask.scope.$eval(asyncTask.expression); } catch (e) { clearPhase(); $exceptionHandler(e); } lastDirtyWatch = null; }
因此,正如我们所看到的,它$$asyncQueue一直运行到,直到它为空,然后执行您的promise中的代码。
因此,正如我们所看到的,更新作用域只是分配给它,如果摘要尚未运行,则摘要将运行,如果是,则将$evalAsync在观察程序运行之前调用promise中运行的代码。如此简单:
myPromise().then(function(result){ $scope.someName = result; });
足够,保持简单。
*注意角度区分抛出与拒绝-默认情况下会记录抛出,并且必须明确记录拒绝