docs: function(arg1, arg2, arg3) {
          var attrs, current, options;
          if (_.isObject(arg1) || isNullOrUndefined(arg1)) {
            attrs = arg1;
            options = arg2;
          } else {
            attrs = {};
            attrs[arg1] = arg2;
            options = arg3;
          }
  
          options = _.clone(options) || {};
          if (options.wait) {
            current = _.clone(this.attributes);
          }
  
          var setOptions = _.clone(options) || {};
          if (setOptions.wait) {
            setOptions.silent = true;
          }
          if (attrs) {
            this.set(attrs, setOptions);
          }
  
          var model = this;
  
          var unsavedChildren = [];
          var unsavedFiles = [];
          AV.Object._findUnsavedChildren(model, unsavedChildren, unsavedFiles);
          if (unsavedChildren.length + unsavedFiles.length > 1) {
            return AV.Object._deepSaveAsync(this, model, options);
          }
  
          this._startSave();
          this._saving = (this._saving || 0) + 1;
  
          this._allPreviousSaves = this._allPreviousSaves || Promise.resolve();
          this._allPreviousSaves = this._allPreviousSaves
            .catch(e => {})
            .then(function() {
              var method = model.id ? 'PUT' : 'POST';
  
              var json = model._getSaveJSON();
              var query = {};
  
              if (model._fetchWhenSave || options.fetchWhenSave) {
                query['new'] = 'true';
              }
              // user login option
              if (options._failOnNotExist) {
                query.failOnNotExist = 'true';
              }
  
              if (options.query) {
                var queryJSON;
                if (typeof options.query.toJSON === 'function') {
                  queryJSON = options.query.toJSON();
                  if (queryJSON) {
                    query.where = queryJSON.where;
                  }
                }
                if (!query.where) {
                  var error = new Error('options.query is not an AV.Query');
                  throw error;
                }
              }
  
              _.extend(json, model._flags);
  
              var route = 'classes';
              var className = model.className;
              if (model.className === '_User' && !model.id) {
                // Special-case user sign-up.
                route = 'users';
                className = null;
              }
              //hook makeRequest in options.
              var makeRequest = options._makeRequest || _request;
              var requestPromise = makeRequest(
                route,
                className,
                model.id,
                method,
                json,
                options,
                query
              );
  
              requestPromise = requestPromise.then(
                function(resp) {
                  var serverAttrs = model.parse(resp);
                  if (options.wait) {
                    serverAttrs = _.extend(attrs || {}, serverAttrs);
                  }
                  model._finishSave(serverAttrs);
                  if (options.wait) {
                    model.set(current, setOptions);
                  }
                  return model;
                },
                function(error) {
                  model._cancelSave();
                  throw error;
                }
              );
  
              return requestPromise;
            });
          return this._allPreviousSaves;
        }