2016-12-20 2 views
0

Я пытаюсь выполнить несколько циклов над объектами firebase с помощью .forEach, и я также использую обещания. Это не работает, как я это планировал. Моя основная проблема заключается в том, что петли внутри моих обещаний полностью завершаются после того, как сама цепочка обещаний завершается. Вот моя функция:Завершение циклов внутри 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

Я никогда раньше не использовал firebase, но похоже, что вы используете '.once' неправильно; по крайней мере, согласно [этим документам] (https://firebase.google.com/docs/database/web/read-and-write). Я думаю, вы хотите использовать '.on ('значение, fn). then (...) 'вместо' .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); 
});