2017-08-01 58 views
1

我遇到了JavaScript承諾的一些問題。這裏是我的代碼:JavaScript多重承諾導致null

//removed code 

我已經添加了一些註釋來解釋我想要做什麼。現在的問題是,我得到receiptID並創建另一個promise variable並將其推入承諾數組中,console.log打印出結果。

但是,在我註釋到該行並嘗試打印出.then()的結果後,將會打印出承諾完成消息,但沒有數組的結果,也沒有錯誤消息,這意味着異步執行不是正確完成。

任何想法如何解決這個問題?先謝謝了!

+0

的可能的複製[爲什麼在。那麼()鏈接未定義的價值承諾?(https://stackoverflow.com/questions/44439596/why-is-value-undefined-at-then-chained-to-諾) –

+0

避免['Promise'構造反模式](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi

+0

我想'innerResult.entries'會失敗 –

回答

0

代碼中沒有任何內容正在等待這些從屬承諾。因爲您沒有從您的處理程序中返回任何內容,所以您的處理程序完成後,立即解析承諾then返回。因此,您正在等待第一級承諾(您推入promises的承諾),但不是那些查詢收據詳細信息的承諾。

承諾的關鍵之一是then返回新的承諾;這是一個管道,其中每一個then(和catch)處理程序可以修改什麼穿過。由then(或catch)返回的承諾將使用then處理程序的返回值進行解析,如果它不是承諾類(「可接受」)值,或者如果它承諾承諾處理返回的處理程序(「可以」)。

所以,你應該從傳播的then處理程序,等待收據的東西;可能是Promise.all的結果。我會把它分解成單獨的功能(在至少兩個:一個獲得外層,不管是什麼,還有一個獲得該層的收據)。

另外請注意,我們沒有理由明確創建你的頂級新的承諾。你已經有一個:從once

如果我明白你想要做的正確的事情,我已經在這裏重新組織了一些基於物品的收據信息,然後讓一個調用獲取收據而不是每個物品的呼叫,並從收據中獲取分支詳細信息。看評論:

const promiseDataList = 
    // Get all receipt items for the category 
    firebase.database().ref('receiptItemIDsByCategory').child(category).once('value').then(itemIds => { 
     // Build a map of receipt info keyed by receipt ID by getting all of the items and, as 
     // we get them, storing the receipt info in the map 
     const receiptMap = new Map(); 
     return Promise.all(itemIds.map(itemSnapshot => { 
      // Get the details of each receipt into a map keyed by receipt ID; since a receipt 
      // can have multiple items, be sure to check the map before adding a new entry 
      return firebase.database().ref('receiptItems').child(itemSnapshot.key).once('value').then(item => { 
       const itemDetail = item.val(); 
       const price = itemDetail.price; 
       const quantity = itemDetail.quantity; 
       const itemTotal = price * quantity; 
       const receiptEntry = receiptMap.get(itemDetail.receiptID); 
       if (receiptEntry) { 
        // We already have this receipt, add to its total 
        receiptEntry.total += itemTotal; 
       } else { 
        // New receipt 
        receiptMap.set(itemDetail.receiptID, {id: itemDetail.receiptID, total: itemTotal}); 
       } 
      }); 
     })).then(() => { 
      // We have the map of receipts we want info for; get all receipts so we can filter 
      // for only the ones we want. (Note: Surely we could use the keys from receiptMap to 
      // limit this Firebase query?) 
      return firebase.database().ref('receipts').once('value').then(receipts => { 
       // Filter out the irrelevant receipts (again, Firebase perhaps could do that for us?) 
       // and then map the remaining ones to objects with the desired information 
       return receipts.filter(receipt => receiptMap.has(receipt.key)).map(receipt => { 
        const branchDetail = receipt.val().branch; 
        const branchName = branchDetail.branchName; 
        const branchAddress = branchDetail.branchAddress; 
        console.log(branchName + ' ' + branchAddress + ' ' + receipt.total); 
        return {branchName, branchAddress, total: receipt.total}; 
       }); 
      }); 
     }); 
    }); 

promiseDataList.then(arr => { 
    console.log('promise done'); 
    for (var i = 0; i < arr.length; i++) { 
     console.log(arr[i].branchName + ' ' + arr[i].branchAddress + ' ' + arr[i].total); 
    } 
}); 

這可能是有點更簡明地寫有箭頭的功能簡潔的形式,但可以在清晰的方式有時會。

+0

對不起,但我是新來的,並沒有那麼熟悉諾言。因此,對於「準備」部分,我應該用query.once和data.forEach替換itemKey部分。那麼解決方案第三行中的返回查詢怎麼樣? – hyperfkcb

+0

@DeniseTan:實際上,「一些準備」應該是像'var itemData = snapshot.val(); var itemKey = snapshot.key;'等等。 'firebase ... once()'是'query'部分。如果您對承諾不太熟悉,我強烈建議先通過一些更簡單的方案來完成此任務。 –

+0

嗨收到receiptID後,我應該根據您的解決方案來做什麼?我被卡在映射和最後的返回聲明那裏。我已經更新了這個問題,你介意幫我看一下嗎? – hyperfkcb