diff --git a/src/ParseObject.js b/src/ParseObject.js
index 87738d56f..430588d2b 100644
--- a/src/ParseObject.js
+++ b/src/ParseObject.js
@@ -1799,6 +1799,102 @@ class ParseObject {
return CoreManager.getObjectController().save(list, saveOptions);
}
+ /**
+ * Saves the given list of Parse.Object.
+ * Will keep trying to save all items lists, even if encountering errors,
+ * up to options.retryMax (default 3).
+ *
+ *
+ * Parse.Object.saveAllSettled([object1, object2, ...], options)
+ * .then((list) => {
+ * // All the objects were saved.
+ * }, (error) => {
+ * // An error occurred while saving one of the objects.
+ * error will contain:
+ *
+ * - message: error message
+ *
- statuses: list of statuses { status : fulfilled | rejected,
+ * reason : ,
+ * fulfilled : }
+ *
+ * });
+ *
+ *
+ * @param {Array} list A list of Parse.Object
.
+ * @param {object} options
+ * Used to pass option parameters to method (optional).
+ * Valid options are:
+ *
+ * - retryMax: Number of times to retry (defualt 3)
+ *
- delay: milliseconds between save requests (default 100)
+ *
+ * @static
+ * @returns {Parse.Object[]}
+ */
+ static saveAllSettled(list: Array, options: RequestOptions = {}) {
+ const saveOptions = {};
+ if (options.hasOwnProperty('retryMax')) {
+ saveOptions.retryMax = options.retryMax;
+ } else {
+ saveOptions.retryMax = 3;
+ }
+ if (options.hasOwnProperty('delay')) {
+ saveOptions.delay = options.delay;
+ } else {
+ saveOptions.delay = 100;
+ }
+
+ list = list || [];
+ let statuses = list.map(function () {
+ return { status: 'init' };
+ });
+ let retryCount = 0;
+
+ return new Promise(function (resolve, reject) {
+
+ function saveRun() {
+ //created a staggered sequence of save calls, delayed by ms
+ let delay = 0;
+ let staggered = list.map( (item, i) => {
+ return new Promise(staggerResolve => {
+ if (item.dirty() && statuses[i].status !== 'fulfilled') {
+ delay += options.delay;
+ setTimeout(() => {
+ staggerResolve(item.save());
+ }, delay)
+ } else {
+ staggerResolve(item);
+ }
+ })
+ });
+
+ Promise.allSettled(staggered).then( (results) => {
+ statuses = results;
+ const successCount = results.reduce( (total, result) => {
+ return total + (result.status === 'fulfilled' ? 1 : 0);
+ }, 0);
+
+ if (successCount === list.length) {
+ //all saved ok
+ resolve(list);
+ } else if (retryCount < options.retryMax) {
+ //try again, with those that failed
+ retryCount++;
+ saveRun(retryCount);
+ } else {
+ //hit the limit - reject
+ reject({
+ message: 'Time Out. Saved ' + successCount + ' of ' + list.length + ' items.',
+ statuses: statuses
+ });
+ }
+ });
+ }
+ saveRun();
+ });
+ }
+
+
/**
* Creates a reference to a subclass of Parse.Object with the given id. This
* does not exist on Parse.Object, only on subclasses.