javascript - 在 angularJS 和 Typescript 中使用 Promise
我有以下函数,我的目标是向 items 列表中推送,当组件可以识别它们的父项时。我的问题是,当我推送到列表时,console.log() 显示对象确实在里面,但当我返回列表并在另一个函数中捕获时,列表中什么都没有。我认为 items 列表在上面的代码执行完成之前就被返回了。
private get_items_for_request() {
return this.Item.forRequest(this.request.id, ['group'])
.then((_items) => {
var items = [];
for (var item of _items) {
return this.ItemComponent.forItem(item.id, ['type'])
.then((_components) => {
for (var component of _components) {
if (component.type.can_identify_item) {
items.push({
group_id: item.group.reference,
identifier_code: this.remove_check_digit_if_necessary(
component.identifier_code),
quantity: 1
});
break;
}
}
}, (reason) => {
this.Toast.error(
this.gettextCatalog.getString('components.load_failed'));
return [];
});
}
return items;
}, (reason) => {
this.Toast.error(
this.gettextCatalog.getString('items.failed_load'));
return [];
});
}
答案#1
恐怕问题出在你的方法上,而不是代码本身。Promise 就是一个承诺——承诺将来某个时间提供数据。所以,当你的函数返回(立即返回)时,Promise 还没有被解决,你的调用函数获取到的数据仍然是空的。我在你的代码中没看到 console.log(),但我怀疑你把它放在了 then() 内部,而 then() 会在数据接收到之后才被调用。所以你会看到数据被记录下来。问题是,到那时 get_items_for_request() 已经返回,你的调用函数也已经继续执行了。
如果你想使用 Promise,你必须使用回调函数,在 Promise 被解决后调用。但是如果你想要实际数据返回给调用者,你需要同步获取数据。
对于同步抓取,请检查此响应。但请注意,同步抓取会影响脚本的响应性。
对于异步获取(使用 promises),你需要定义一个回调函数,该函数在所有数据获取完成后调用。我不会尝试修复你的代码,但它的结构应该大致如下所示(用 JavaScript 表示)。不过请记住,这只是一个草图。
function get_items_for_request(onSuccess) {
var items = []
var total = -1
var sofar = 0;
this.Item.forRequest(this.request.id, ['group'])
.then(function (_items) {
var items = [];
total = _items.length // remember how many nested calls will be made
for (var item of _items) {
this.ItemComponent.forItem(item.id, ['type'])
.then(function (_components) {
// push received data to the items array here
sofar++
if (sofar == total) { // all done
onSuccess(items)
}
}
}
}
}
答案#2
在第一个 promise 回调中,你有两个 return,只有第一个会执行。在第一个 for 之后你返回了一个 promise,而你将其解析为 undefined。你应该等待一个 promise 数组,每个 promise 对应一个 this.ItemComponent.forItem 调用。
Promise.all 可以帮助做到这一点: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
你应该这样做:
return this.Item.forRequest(this.request.id, ['group']).then((_items) => {
return Promise.all(_items.map(function (item) {
return this.ItemComponent.forItem(item.id, ['type']).then((_components) => {
for (var component of _components) {
if (component.type.can_identify_item) {
return {
group_id: item.group.reference,
identifier_code: this.remove_check_digit_if_necessary(
component.identifier_code),
quantity: 1
};
}
}
}, (reason) => {
this.Toast.error(
this.gettextCatalog.getString('components.load_failed'));
return [];
});
}));
}, (reason) => {
this.Toast.error(
this.gettextCatalog.getString('items.failed_load'));
return [];
} )
如果你只想要一个项目,请在结果数组中找到第一个非假值元素
