2016-05-13 91 views
2

我有以下功能,我的目標是推到物品清單,當組件可以識別他們的父項目。 我的問題是,當我推到列表console.log()顯示我的對象在那裏,但是當我返回列表並在另一個函數中捕獲它時,列表中沒有任何內容。 我認爲物品清單是在上面的代碼完成之前返回的。承諾與angularJS和Typescript

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

回答

2

恐怕麻煩在於你的方法,而不是代碼本身。承諾就是這樣 - 未來一段時間的數據承諾。所以,當函數返回(立即)時,promise還沒有解決,你的調用函數捕獲的數據仍然是空的。我沒有在你的代碼中看到console.log(),但是會懷疑你把它放在那裏()內的某個地方,一旦收到數據就會調用它。所以你會看到數據被記錄。麻煩就在那個時候,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) 
      } 
      } 
     } 
    } 
} 
0

在第一個承諾回調中,您有兩個回報,只有第一個回報,只有第一個回報。您在第一個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元素

+0

@GiftZwergrapper如果你想接收一個工作代碼,你必須鏈接一個plunkr例子,或者至少整個文件。我不確定你的期望是什麼,我們不是媒介。 如果您使用Angular 1,'$ q'服務就是您的Promise庫。 –

+2

@GiftZwergrapper同樣,請注意,我指出的錯誤仍然存​​在,您在這裏的投票有點積極。 –

+0

在角度上,你可以使用'$ q.all'來達到同樣的目的 – Icycool