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:
+   * 
+   * });
+   * 
+ * + * @param {Array} list A list of Parse.Object. + * @param {object} options + * Used to pass option parameters to method (optional). + * Valid options are: + * + * @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.