使用 angularJS 和 Typescript 的 Promise

Posted

技术标签:

【中文标题】使用 angularJS 和 Typescript 的 Promise【英文标题】:Promises with angularJS and Typescript 【发布时间】:2016-09-09 10:30:58 【问题描述】:

我有以下功能,我的目标是在组件可以识别其父项时推送到项目列表。 我遇到的问题是,当我推送到列表时,console.log() 向我显示对象在其中,但是当我返回列表并在另一个函数中捕获它时,列表中没有任何内容。 我认为项目列表是在上面的代码完成之前返回的。

 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 尚未解决,并且您的调用者函数捕获的数据仍然是空的。我在您的代码中没有看到 console.log(),但怀疑您将它放在 then() 中的某个位置,一旦收到数据就会调用它。因此,您将看到正在记录的数据。麻烦的是到那时 get_items_for_request() 已经返回并且您的调用者函数已经继续。

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

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

对于异步获取(使用 Promise),您需要定义在获取所有数据后调用的回调。我不会尝试修复您的代码,但它应该遵循以下 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 回调中,你有两个返回,只有第一个运行。你在第一个for 之后返回一个承诺,你将其解析为undefined。您应该等待一组 promise,每个 promise 对应一个 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 [];
     )

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

【讨论】:

@GiftZwergrapper 如果你想收到一个工作代码,你必须链接一个 plunkr 示例,或者至少是整个文件。我不知道你期待什么,我们不是媒介。如果你使用 Angular 1,$q 服务就是你的 Promise 库。 @GiftZwergrapper 也请注意,我指出的错误仍然存​​在,您在这里的反对意见有点激进。 在 Angular 中,您可以使用 $q.all 实现相同目的 $q.all 更好,因为它会触发摘要循环。 Promise.all 可能不会。

以上是关于使用 angularJS 和 Typescript 的 Promise的主要内容,如果未能解决你的问题,请参考以下文章

使用 TypeScript 和注入的 AngularJS 过滤器

带有 ControllerAs 和 TypeScript 类的 AngularJs 指令

使用 angularJS 和 Typescript 的 Promise

使用 typescript 的 IResourceClass 扩展 angularjs 的 $resource

迈向angularjs2系列:typescript指南

AngularJS 和 Typescript:如何将类/类型分配为指令的控制器?