【问题标题】:$http promise chain running in wrong order$http 承诺链以错误的顺序运行
【发布时间】:2015-02-09 02:17:08
【问题描述】:

我是 angularjs 的新手。我的目标很简单。我想进行 ajax 调用来获取数据,一旦完成,我想进行第二次调用以获取另一组数据,该数据依赖于第一组中的信息。

我正在尝试利用承诺机制来做到这一点,这样我就可以利用链接而不是嵌套的 ajax 调用,并更好地保留拥有可以根据需要捆绑在一起的独立函数的能力。

我的代码如下所示:

var promiseGetWorkTypes = function ($q, $scope, $http) {
	console.log("promiseGetWorkTypes");

	return $q(function (resolve, reject) {
		$http({
			method: 'GET',
			url: '/WorkTypes'
		}).then(
			function (payload) {
				console.log("Got workttypegroups")
				console.log(payload);

				$scope.WorkTypeGroups = payload.data;

				console.log("End of worktypegroups");
				resolve(payload);
			},
			function (payload) {
				reject(payload);
			});
	});
};

var promiseGetRecentActivities = function ($q, $scope, $http) {
	console.log("promiseGetRecentActivities");

	return $q(function (resolve, reject) {
		$http({
			method: 'GET',
			url: '/RecentHistory'
		}).then(
			function (payload) {
				$scope.RecentActivities = payload.data;

				resolve(payload);
			},
			// data contains the response
			// status is the HTTP status
			// headers is the header getter function
			// config is the object that was used to create the HTTP request
			function (payload) {
				reject(payload);
			});
	});
};

var index = angular.module("index", []);

index
.controller('EntitiesController', function ($scope, $http, $timeout, $q) {
	promiseGetWorkTypes($q, $http, $scope)
		.then(promiseGetRecentActivities($q, $http, $scope));
}

但是,当我查看调试控制台时,我发现对“promiseGetRecentActivities”的调用是在“promiseGetWorkTypes”的 Ajax 处理调用发生之前开始的。

我在这里遗漏了什么或做错了什么?

【问题讨论】:

  • 不,不是$q.all()。 OP 希望连续进行两个 ajax 调用。
  • @BenjaminGruenbaum,您的链接涉及带有承诺的反模式,并确定了对延迟承诺的不必要使用。我的代码确实包含不必要的复杂性,因为 $http 将返回一个不需要由 $q 包装的承诺。这是因为我之前认为这可能是我最初的 $http 调用承诺不起作用的原因。显然情况并非如此。我已经修改了我的实际项目,我只是想确保阅读此内容的任何人都知道在这种情况下使用 $q 是不必要的并且应该避免。感谢您指出这一点。

标签: javascript ajax angularjs promise angular-promise


【解决方案1】:

当你写作时

promiseGetWorkTypes($q, $http, $scope).then(promiseGetRecentActivities($q, $http, $scope));

在评估此行时调用promiseGetActivites。您应该能够将对 promiseGetActivities 的调用包装在另一个函数中以延迟调用,直到第一个承诺已解决以使调用按顺序运行:

promiseGetWorkTypes($q, $http, $scope).then(function() {
  promiseGetRecentActivities($q, $http, $scope);
});

原因与 then 内部发生的事情无关,而是由于 Javascript 语法。以下:

myFunc1(myFunc2());

将调用myFunc2()结果 传递给myFunc1,并且不是myFunc2 函数的引用。所以从逻辑上讲,myFunc2 必须在myFunc1 之前运行。如果你写了

myFunc1(myFunc2);

然后myFunc1 将收到对myFunc2 的引用,因此myFunc1 将在myFunc2 之前运行(事实上,myFunc2 只有在myFunc1 内部的某个地方有调用它的代码时才会运行)。

内联/匿名定义函数不会改变这种行为。要将匿名函数的结果传递给另一个函数,您可以执行以下操作

myFunc1((function() {
  return 'something';
})());

它将首先评估匿名函数,作为其返回值,'something' 将被传递给myFunc1。要传递对匿名函数的引用,您可以执行以下操作:

myFunc1(function() {
  return 'something';
});

然后取决于myFunc1 是否会调用传递给它的函数。

回到你的问题,你的代码:

promiseGetWorkTypes($q, $http, $scope).then(promiseGetRecentActivities($q, $http, $scope));

正在将promiseGetRecentActivities($q, $http, $scope) 的结果传递给then,因此它必须在then 运行之前运行,因此当然不会等待promiseGetWorkTypes 的承诺得到解决。您似乎想要的是传递一个函数,该函数在调用时运行promiseGetRecentActivities($q, $http, $scope),这就是

promiseGetWorkTypes($q, $http, $scope).then(function() {
  promiseGetRecentActivities($q, $http, $scope);
});

会。

作为旁注,将$q$http 等传递给各种功能似乎有点不寻常/过于复杂,但我认为可能超出了这个问题的范围,通过替代方案。

【讨论】:

  • 哇!这似乎奏效了,但我不知道为什么。我原以为“.then”调用会推迟调用传入的任何函数变量,直到先前的承诺得到解决。如果它立即调用“promiseGetRecentActivities”,为什么不立即调用匿名函数呢?是否有某种逻辑在对“.then”的调用中寻找无参数或未命名的方法?
  • @dshockey 我在回答中添加了更多内容以尝试澄清
  • 这一切都是有道理的,我应该意识到我正在这样做。我想我在将函数视为一等对象时迷失了方向,没有注意到我正在调用函数并传递结果,就像在任何其他语言中一样。感谢您澄清这一点。我只剩下一个问题:为什么“.then”允许函数引用以外的任何东西?它将如何处理任何其他数据?我很惊讶我在尝试将调用结果传递给“promseGetRecentActivities”而不是函数引用时没有遇到运行时错误。
  • @dshockey 我认为角度 $q 实现试图符合 Promises/A+ 状态 If onFulfilled is not a function, it must be ignored
  • 谢谢!我非常感谢您的答案和洞察力!
猜你喜欢
  • 1970-01-01
  • 2020-02-12
  • 1970-01-01
  • 2020-06-16
  • 1970-01-01
  • 1970-01-01
  • 2022-12-11
  • 1970-01-01
  • 2020-04-25
相关资源
最近更新 更多