2016-12-20 111 views
0

我正在嘗試使用.forEach完成firebase對象上的幾個循環,並且我還使用了promise。這並不是我計劃的方式。我的基本問題是,承諾鏈本身完成後,我的承諾中的循環完好無損。這裏是我的功能:完成node.js內部的循環承諾

var queue = new Queue(productUpdateQueue, function(data, progress, resolve, reject) { 

    var incomingUpdateData = data; 
    var receiptID = incomingUpdateData.receiptID; 
    var userID = incomingUpdateData.userID; 
    var oldProductID = incomingUpdateData.oldProductID; 
    var newProductID = incomingUpdateData.newProductID; 
    var newReceipt = incomingUpdateData.newReceipt; 

    var postID = ""; 

    var updateObject = {}; 

    updateObject['usersPrivate/'+userID+'/receipts/'+receiptID+'/items/'+oldProductID] = null; 
    updateObject['usersPrivate/'+userID+'/receipts/'+receiptID+'/items/'+newProductID] = newReceipt; 

    clicks.child('VigLink').orderByChild('item').equalTo(oldProductID).once('value', function(cuidSnapshot) { 
     return cuidSnapshot.forEach(function(cuidSnapshot) { 
      var cuid = cuidSnapshot.key; 
      updateObject['clicks/VigLink/'+cuid+'/item'] = newProductID; 
      console.log('one'); 
      progress(20); 
     }); 
    }).then(function() { 
     return userReceiptMetrics.child(userID).child('receipts').child(receiptID).child('items').child(oldProductID).once('value', function(oldSnapshot) { 
      var data = oldSnapshot.val() 
      updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/items/'+oldProductID] = null 
      updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/items/'+newProductID] = data 
      if (data != null) { 
       updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/itemIDs/'+newProductID] = now 
       updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/itemIDs/'+oldProductID] = null 
      }; 
      console.log('two'); 
      progress(40); 
     }); 
    }).then(function() { 
     return userReceiptMetrics.child(userID).child('shops').child(oldProductID).once('value', function(oldSnapshot) { 
      var data = oldSnapshot.val() 
      updateObject['userReceiptMetrics/'+userID+'/shops/'+oldProductID] = null; 
      updateObject['userReceiptMetrics/'+userID+'/shops/'+newProductID] = data; 
      if (data != null) { 
       updateObject['userReceiptMetrics/'+userID+'/shopIDs/'+newProductID] = now; 
       updateObject['userReceiptMetrics/'+userID+'/shopIDs/'+oldProductID] = null; 
      }; 
      console.log('three'); 
      progress(60); 
     }); 
    }).then(function() { 
     posts.once('value', function(postSnapshot) { 
      // use Promise.all and Array#map to wait for all these queries to finish 

      var allPosts = postSnapshot.val() 
      var postKeys = Object.keys(allPosts) 

      return Promise.all(postKeys.map(function(postKey) { 
       var postID = postKey; 

       return posts.child(postID).child('items').child(oldProductID).once('value', function(itemSnapshot) { 

        return itemSnapshot.forEach(function(itemSnapshot) { 
         var itemData = itemSnapshot.val() 
         console.log('post snapshot'+ itemData); 
         updateObject['posts/'+postID+'/items/'+oldProductID] = null 
         updateObject['posts/'+postID+'/items/'+newProductID] = itemData 
        }); 
       }); 
      })); 
     }); 
    }).then(function() { 
     // Move to next item 
     return console.log('hey look here'+updateObject['posts/'+postID+'/items/'+newProductID]); 
     return firebaseRoot.update(updateObject, function(error) { 
      if (error) { 
       console.log("Error updating data:", error); 
       reject() 
      } else { 
       progress(100); 
       // resolve(); 
       console.log('four'); 
      } 
     }); 
    }).then(function() { 
     // Move to next item 
     return console.log('second one'+updateObject['posts/'+postID+'/items/'+newProductID]); 
     return firebaseRoot.update(updateObject, function(error) { 
      if (error) { 
       console.log("Error updating data:", error); 
       reject() 
      } else { 
       progress(100); 
       // resolve(); 
       console.log('four'); 
      } 
     }); 
    }); 

    // Finish the task asynchronously 
    setTimeout(function() { 
     reject(); 
    }, 10000); 
}); 

,這裏是輸出:

one 
two 
three 
hey look hereundefined 
second oneundefined 
post snapshot[object Object] 
post snapshot[object Object] 
post snapshot[object Object] 
post snapshot[object Object] 
post snapshot[object Object] 
post snapshot[object Object] 
post snapshot[object Object] 
post snapshot[object Object] 

我想我可能會錯誤地使用承諾,但我不知道。

+0

我從來沒有火力點前使用,但它看起來像你使用'.once'不正確;至少根據[這些文檔](https://firebase.google.com/docs/database/web/read-and-write) - 我想你的意思是使用'.on('value,fn)。然後...)'而不是'.once'。除此之外,'forEach'返回'undefined',所以你可能想要返回/解決比這更有意義的事情。也許看看'Array.prototype.map'。對不起,我無法提供更多幫助。 – naomik

回答

0

我發現我應該使用Promise.all()以等待我的forEach循環完成。下面是我用來解決我的問題代碼,即可享受:

var queue = new Queue(productUpdateQueue, function(data, progress, resolve, reject) { 

    var incomingUpdateData = data; 
    var receiptID = incomingUpdateData.receiptID; 
    var userID = incomingUpdateData.userID; 
    var oldProductID = incomingUpdateData.oldProductID; 
    var newProductID = incomingUpdateData.newProductID; 
    var newReceipt = incomingUpdateData.newReceipt; 

    var postID = "-KZOO0UII67uOmYo6DJh"; 

    var postKeys = []; 

    var updateObject = {}; 

    updateObject['usersPrivate/'+userID+'/receipts/'+receiptID+'/items/'+oldProductID] = null; 
    updateObject['usersPrivate/'+userID+'/receipts/'+receiptID+'/items/'+newProductID] = newReceipt; 

    return clicks.child('VigLink').orderByChild('item').equalTo(oldProductID).once('value', function(cuidSnapshot) { 
     return cuidSnapshot.forEach(function(cuidSnapshot) { 
      var cuid = cuidSnapshot.key; 
      updateObject['clicks/VigLink/'+cuid+'/item'] = newProductID; 
      progress(10); 
     }); 
    }).then(function() { 
     return userReceiptMetrics.child(userID).child('receipts').child(receiptID).child('items').child(oldProductID).once('value', function(oldSnapshot) { 
      var data = oldSnapshot.val() 
      updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/items/'+oldProductID] = null 
      updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/items/'+newProductID] = data 
      if (data != null) { 
       updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/itemIDs/'+newProductID] = now 
       updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/itemIDs/'+oldProductID] = null 
      }; 
      progress(25); 
     }); 
    }).then(function() { 
     return userReceiptMetrics.child(userID).child('shops').child(oldProductID).once('value', function(oldSnapshot) { 
      var data = oldSnapshot.val() 
      updateObject['userReceiptMetrics/'+userID+'/shops/'+oldProductID] = null; 
      updateObject['userReceiptMetrics/'+userID+'/shops/'+newProductID] = data; 
      if (data != null) { 
       updateObject['userReceiptMetrics/'+userID+'/shopIDs/'+newProductID] = now; 
       updateObject['userReceiptMetrics/'+userID+'/shopIDs/'+oldProductID] = null; 
      }; 
      progress(40); 
     }); 
    }).then(function() { 
     progress(55); 
     return posts.orderByChild('receipt').equalTo(receiptID).once('value'); 
    }).then(function(postSnapshot) { 
     return postSnapshot.forEach(function(post) { 
      progress(70); 
      postKeys.push(post.key) 
     }); 
    }).then(function() { 
     return Promise.all(postKeys.map(function(postKey) { 
      return posts.child(postKey).child('items').child(oldProductID).once('value', function(itemSnapshot) { 
       var itemData = itemSnapshot.val() 
       updateObject['posts/'+postKey+'/items/'+oldProductID] = null; 
       updateObject['posts/'+postKey+'/items/'+newProductID] = itemData; 
      }); 
     })).then(function(results) { 
      progress(85); 
      return results; 
     }); 
    }).then(function() { 
     return firebaseRoot.update(updateObject, function(error) { 
      if (error) { 
       console.log("Error updating data:", error); 
       reject() 
      } else { 
       progress(100); 
       resolve(); 
      } 
     }); 
    }); 

    // Finish the task asynchronously 
    setTimeout(function() { 
     reject(); 
    }, 10000); 
});