这个 promise 嵌套可以改成 chaining 吗?
Can this promise nesting be changed to chaining?
这是伪场景
| then (items) | then (items, actions)
getItems() | getActions(for:items) | apply(actions -> items)
:promise | :promise | model <= items
| | :synchronous
所以换句话说:
- 我需要获取全局项目列表。
- 很好。已获取项目。
- 请求用户接管之前获取的项目的操作。
- 很好。获取的操作。
- 对项目列表应用操作。
- 将项目放在模型上并显示在视图中。
这有点像我正在使用的代码
return itemsResource
.getItems(userId)
.$promise
.then(function(items) {
return actionsResource
.getActions(items.map(i => i.id)) // pseudo mapper code here
.$promise
.then(function(actions) { // THIS IS NESTED so it sees both promise results
return [items, actions];
});
})
.then(helper.spread(function(items, actions) {
applyActions(items, actions);
$scope.model.items = items;
return items;
}));
如您所知,我最初不能使用 $q.all
,因为第二个(操作)承诺取决于第一个(项目)的结果。
为什么不对项目进行 return 操作? 因为我正在为所有用户缓存项目,所以项目获取非常快。这类似于 Whosebug 的工作方式。他们只是 return 问题,而不考虑用户的请求。然后他们随后还请求首选和忽略的标签,并应用于获取的问题。这可以很好地扩展,否则 SO 将需要更多的服务器来处理所有用户的初始问题列表,因为每个用户的请求都会产生不同的结果,因此缓存没有多大意义。
为什么不在获取后立即将项目应用到 $scope
? 这将消除额外的嵌套 then
,是的。但我没有这样做,因为之后还有几个步骤,并且每次其中一项承诺得到解决时,至少会执行一个 $digest
周期。对于许多项目(相当复杂的对象),这可以解释相当多的处理。这就是我坚持将项目传递到视图的原因,直到最后一刻。
问题
除了这两个解决方法之外,还有什么方法可以避免嵌套 then
:
- 尽快将项目应用到
$scope
- 将项目保存到局部变量并在以后使用
如果可能的话,我想在不引入额外资源的情况下尽可能地扁平化我的代码?
如何将 items->actions 链的结果包装在一个 promise 中?像
return $q(function(resolve, reject) {
var outerItems;
itemsResource.getItems(userId).$promise
.then(getActions)
.then(function (actions) {
resolve([outerItems, actions]);
})
.catch(function (err) { reject(err); });
function getActions(items) {
outerItems = items;
return actionsResource.getActions(items).$promise
}
}).then(function (itemAndActions) {
var items = itemsAndActions[0],
actions = itemsAndActions[1];
return helper.spread(function (items, actions) {
applyActions(items, actions);
$scope.model.items = items;
return items;
})
});
除非我遗漏了什么,否则这应该相当简单,不是吗?
(为了清晰起见,我简化了您的一些内部函数签名)
itemsResource.getItems(userId)
.then(function(items) {
return $q.all({
items: items,
actions: actionResource.getActions(items)
});
})
.then(function(data) {
applyActions(data.items, data.actions);
$scope.model.items = data.items;
return data.items;
});
plunker 供说明
这是伪场景
| then (items) | then (items, actions)
getItems() | getActions(for:items) | apply(actions -> items)
:promise | :promise | model <= items
| | :synchronous
所以换句话说:
- 我需要获取全局项目列表。
- 很好。已获取项目。
- 请求用户接管之前获取的项目的操作。
- 很好。获取的操作。
- 对项目列表应用操作。
- 将项目放在模型上并显示在视图中。
这有点像我正在使用的代码
return itemsResource
.getItems(userId)
.$promise
.then(function(items) {
return actionsResource
.getActions(items.map(i => i.id)) // pseudo mapper code here
.$promise
.then(function(actions) { // THIS IS NESTED so it sees both promise results
return [items, actions];
});
})
.then(helper.spread(function(items, actions) {
applyActions(items, actions);
$scope.model.items = items;
return items;
}));
如您所知,我最初不能使用 $q.all
,因为第二个(操作)承诺取决于第一个(项目)的结果。
为什么不对项目进行 return 操作? 因为我正在为所有用户缓存项目,所以项目获取非常快。这类似于 Whosebug 的工作方式。他们只是 return 问题,而不考虑用户的请求。然后他们随后还请求首选和忽略的标签,并应用于获取的问题。这可以很好地扩展,否则 SO 将需要更多的服务器来处理所有用户的初始问题列表,因为每个用户的请求都会产生不同的结果,因此缓存没有多大意义。
为什么不在获取后立即将项目应用到 $scope
? 这将消除额外的嵌套 then
,是的。但我没有这样做,因为之后还有几个步骤,并且每次其中一项承诺得到解决时,至少会执行一个 $digest
周期。对于许多项目(相当复杂的对象),这可以解释相当多的处理。这就是我坚持将项目传递到视图的原因,直到最后一刻。
问题
除了这两个解决方法之外,还有什么方法可以避免嵌套 then
:
- 尽快将项目应用到
$scope
- 将项目保存到局部变量并在以后使用
如果可能的话,我想在不引入额外资源的情况下尽可能地扁平化我的代码?
如何将 items->actions 链的结果包装在一个 promise 中?像
return $q(function(resolve, reject) {
var outerItems;
itemsResource.getItems(userId).$promise
.then(getActions)
.then(function (actions) {
resolve([outerItems, actions]);
})
.catch(function (err) { reject(err); });
function getActions(items) {
outerItems = items;
return actionsResource.getActions(items).$promise
}
}).then(function (itemAndActions) {
var items = itemsAndActions[0],
actions = itemsAndActions[1];
return helper.spread(function (items, actions) {
applyActions(items, actions);
$scope.model.items = items;
return items;
})
});
除非我遗漏了什么,否则这应该相当简单,不是吗?
(为了清晰起见,我简化了您的一些内部函数签名)
itemsResource.getItems(userId)
.then(function(items) {
return $q.all({
items: items,
actions: actionResource.getActions(items)
});
})
.then(function(data) {
applyActions(data.items, data.actions);
$scope.model.items = data.items;
return data.items;
});
plunker 供说明