AngularJS Promises $q.all and SignalR
我检查了有关诺言的答案,但是我无法使我的代码正常工作(也许我在其他地方做错了什么大事)
通常,我正在使用AngularJS和SignalR进行小型测试应用程序。我有如下所示的signalR服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | (function () { 'use strict'; var serviceId = 'signalRSvc'; angular.module('app').service(serviceId, ['$rootScope', signalrcontext]); function signalrcontext( $rootScope) { var performanceHub = null; var connection = null; var service = { initialize: initialize, getPerformanceCounters: getPerformanceCounters, getAllValues: getAllValues }; return service; function initialize() { connection = $.connection; performanceHub = connection.webServicePerformanceHub; connection.hub.logging = true; performanceHub.client.updatePerformanceData = function(performanceData) { $rootScope.$emit("updatePerformanceData", performanceData); }; return connection.hub.start(); }; function getPerformanceCounters() { return performanceHub.server.getPerformanceCounters(); }; function getAllValues(id) { return performanceHub.server.getAllValues(id); }; } })(); |
我要做的是初始化SignalR,然后执行getPerformanceCounters()方法,该方法将下载要呈现的计数器列表(以对象数组形式返回),然后为每个计数器获取数据,并且问题开始了。根据MS文档,SignalR代理方法正在返回Promise。我已经编写了这段代码,但我不知道为什么它不能在步骤getAllValues上工作(根据此答案,AngularJS Promises,$ q,推迟它应该可以工作)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function initSignalR() { return signalRSvc.initialize().then(function() { return signalRSvc.getPerformanceCounters(); }).then(function(configurations) { log('performance counters configuration downloaded'); return getAllValues(configurations); }).then(function (resultData) { vm.resultData = resultData; }); } function getAllValues(configurations) { var promises = new Array(); angular.forEach(configurations, function(configuration) { promises.push(signalRSvc.getAllValues(configuration.Id)); }); return $q.all(promises); } |
据我所知,最后一次应该在对signalRSvc.getAllValues的所有"调用"完成后执行,并且resultData应该包含从那些Promise返回的对象数组。取而代之的是,我得到了一些甚至不是数组的垃圾。
令人惊讶的(当然对我来说),当我做这样的事情
1 2 3 4 5 6 7 8 9 10 11 | function getAllValues(configurations) { var promises = new Array(); angular.forEach(configurations, function(configuration) { promises.push(signalRSvc.getAllValues(configuration.Id)); }); return $q.all(promises).then(function(resultData) { //here result data is fine!! }); } |
嵌套则结果数据就很好了(但是,解决Promise的顺序就搞砸了)。
由于我没主意,请多多帮助。
我的朋友Yan Yankowski为AngularJS编写了一个很棒的SignalRpackage器。您可以从GitHub下载它,
该package器还使用$ q promises获得结果。
示例:
1 | hubFactory.getHub("myHub").run("myMethod", param_1, param_2, .... param_n).then ( function(responseData) {} ) |
问题似乎与SingalR返回的Promise有关(我的团队同事发现了这一点)。 SignalR返回的jQuery Promise在所有情况下均与AngularJS Promise不兼容。解决方案是用$ q.whenpackage来自signalR代理的方法。现在一切正常。
固定代码(仍然包含与SignalR相关的其他问题)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ..... return service; function initialize() { connection = $.connection; performanceHub = connection.webServicePerformanceHub; connection.hub.logging = true; performanceHub.client.updatePerformanceData = function(performanceData) { $rootScope.$emit("updatePerformanceData", performanceData); }; return $q.when(connection.hub.start(); }; function getPerformanceCounters() { return $q.when(performanceHub.server.getPerformanceCounters()); }; function getAllValues(id) { return $q.when(performanceHub.server.getAllValues(id)); }; ..... |
以前无法运行的Promise链现在可以正常运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | function initSignalR() { return signalRSvc.initialize().then(function () { return signalRSvc.getPerformanceCounters(); }).then(function (configurations) { chartConfigurations = configurations; return getAllValues(configurations); }).then(function (chartData) { angular.forEach(chartData, function(value, key) { chartConfigurations[key].chartData = convertToChartDataset(value); chartConfigurations[key].options = { animation: false }; }); vm.configurations = chartConfigurations; }); } function getAllValues(configurations) { var promises = []; $.each(configurations, function (index, value) { promises.push(signalRSvc.getAllValues(value.Id)); }) return $q.all(promises); } |
您可以将initSignalR()更改为以下内容吗?
1 2 3 4 5 6 7 8 9 10 | function initSignalR() { return signalRSvc.initialize().then(function() { return signalRSvc.getPerformanceCounters(); }).then(function(configurations) { log('performance counters configuration downloaded'); getAllValues(configurations).then(function (resultData) { vm.resultData = resultData; }); }); } |
我知道它不是很漂亮,但是很显然,即使$ q promises有自己的then方法,jQuery的then方法也显然不能正确地解开$ q promises。