我正在关注AngularJS关于Q实现$q的文档的帮助.我从
https://docs.angularjs.org/api/ng/service/$q尝试了以下代码
// for the purpose of this example let's assume that variables `$q`,`scope` and `okToGreet` // are available in the current lexical scope (they Could have been injected or passed in). function asyncGreet(name) { var deferred = $q.defer(); setTimeout(function() { // since this fn executes async in a future turn of the event loop,we need to wrap // our code into an $apply call so that the model changes are properly observed. scope.$apply(function() { deferred.notify('About to greet ' + name + '.'); if (okToGreet(name)) { deferred.resolve('Hello,' + name + '!'); } else { deferred.reject('Greeting ' + name + ' is not allowed.'); } }); },1000); return deferred.promise; } var promise = asyncGreet('Robin Hood'); promise.then(function(greeting) { alert('Success: ' + greeting); },function(reason) { alert('Failed: ' + reason); },function(update) { alert('Got notification: ' + update); });
我的理解是这里的$scope.apply是给回调Angular的上下文并确保可以访问$scope下的变量.
但在下面比较$q和Kris Kowal的Q时,测试代码如下:
it('should simulate promise',inject(function($q,$rootScope) { var deferred = $q.defer(); var promise = deferred.promise; var resolvedValue; promise.then(function(value) { resolvedValue = value; }); expect(resolvedValue).toBeUndefined(); // Simulate resolving of promise deferred.resolve(123); // Note that the 'then' function does not get called synchronously. // This is because we want the promise API to always be async,whether or not // it got called synchronously or asynchronously. expect(resolvedValue).toBeUndefined(); // <= so the deferred is not resolved without the 'apply'? // Propagate promise resolution to 'then' functions using $apply(). $rootScope.$apply(); expect(resolvedValue).toEqual(123); }));
它说$rootScope.$apply()是将promise解析传播到’then’.我很困惑…所以不使用apply,deferred.resolve实际上不会解决?
解决方法
这个文件很糟糕.
所以$q的问题是当你的promise被解决时(也可能是拒绝或通知),它会在$rootScope.evalAsync
内调用你的处理程序,这确保在调用之后它会触发摘要,因此你的应用程序的其余部分可以有有机会更新或以其他方式响应变化,就像我们喜欢的那样.
正如你所发现的那样,it works just fine without the explicit $apply
in an example app.然而,他们正在进行显式$apply的原因是因为使用$evalAsync的自动化在测试中同步运行时没有机会工作,而不是因为你的应用程序需要Just Work ™.
使用一些其他值得注意的服务来扩充以在angular-mock.js中进行测试,比如$http和$timeout,我们可以在我们想要模拟异步http请求/响应或超时(例如)时显式刷新.相当于等待被唤醒的东西是触发摘要,它将在适当的上下文中调用你的promise处理程序.这是通过$apply或$digest完成的,因此你在他们的例子中看到它的原因……因为他们的例子是作为同步测试编写的.
文档应该解释您需要做什么才能使测试工作与应用程序本身应该关注什么以完成工作之间的区别.文档有一个习惯,就是以测试事实为例,它只会让人感到困惑.
希望有所帮助.