angularJS 和 Typescript 的承诺

Promises with angularJS and Typescript

我有以下功能,我的目标是推送到项目列表,当组件可以识别它们的父项目时。 我遇到的问题是,当我推送到列表时 console.log() 显示对象在那里,但是当我 return 列表并在另一个函数中捕获它时,什么也没有在列表中。 我认为项目列表在上面的代码完成之前 returned。

 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 [];
     });
 }

在第一个 promise 回调中,你有两个 returns,只有第一个运行。您 return 在第一个 for 之后做出承诺,您将其解析为 undefined。您应该等待一系列承诺,每个承诺对应一个 this.ItemComponent.forItem 调用。

Promise.all 对此有帮助:https://developer.mozilla.org/en-US/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 [];
    } )

如果您只想要一个项目,请在结果数组中找到第一个非 falsy 元素

恐怕问题出在你的方法上,而不是代码本身。承诺就是 - 未来某个时间的数据承诺。因此,当您执行 returns 函数(立即)时,promise 尚未解析,您的调用函数捕获的数据仍然为空。我在你的代码中没有看到 console.log(),但我怀疑你把它放在 then() 的某个地方,一旦收到数据就会调用它。所以你会看到数据被记录下来。问题是那个时候 get_items_for_request() 已经返回并且你的调用函数已经移动了。

如果你想使用一个承诺,你必须使用一个回调,一旦承诺被解决就被调用。但是,如果您希望将实际数据返回给调用者,则需要同步获取数据。

对于同步提取,检查this response。但要注意同步获取会损害脚本的响应能力。

对于异步获取(使用 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)
             }
          }
       }
   }
}