Javascript 在回调时不设置主干存储
我的web应用程序中有拖放功能。当用户在拖放后释放鼠标时,对象的位置将使用模型上主干的save()方法保存到服务器。当服务器响应时,它会使用返回的属性在模型上触发set()。但是,在服务器处理请求时,用户可能已经再次将对象拖动到其他位置。这会导致问题,因为服务器的响应现在将覆盖浏览器中对象的设置 是否有办法防止主干在save()之后从服务器获得响应后执行set()?查看“wait”选项,默认情况下,它应设置为false,这意味着在调用save()后应立即设置模型字段。您可以设置{wait:true}使主干网在设置更新的模型字段值之前等待服务器回复 从您描述的行为来看,应用程序中的wait选项似乎设置为true 进一步详情:Javascript 在回调时不设置主干存储,javascript,backbone.js,Javascript,Backbone.js,我的web应用程序中有拖放功能。当用户在拖放后释放鼠标时,对象的位置将使用模型上主干的save()方法保存到服务器。当服务器响应时,它会使用返回的属性在模型上触发set()。但是,在服务器处理请求时,用户可能已经再次将对象拖动到其他位置。这会导致问题,因为服务器的响应现在将覆盖浏览器中对象的设置 是否有办法防止主干在save()之后从服务器获得响应后执行set()?查看“wait”选项,默认情况下,它应设置为false,这意味着在调用save()后应立即设置模型字段。您可以设置{wait:tru
另一件需要记住的重要事情是主干网只设置您从被调用的Web服务返回的更新字段的子集,因此,如果您不返回任何字段,则将不设置任何字段。以前在执行系统时有类似的用例,尽管这更麻烦,因此我们需要真正覆盖模型
set()
函数。尽管对于这种情况,有两种相对简单的方法可用
可以替代模型函数。或者,您可以对save()
调用返回的jqXHR对象调用abort()
为保存编写另一个函数,使用该函数代替保存 在模型中:
var myModel = Backbone.Model.extend({
savePosition: function(){
var model = this;
$.ajax({
type : "POST",
cache: false,
dataType : 'json',
contentType : 'application/json',
data:JSON.stringify(data),
url : "urlToSave",
success:function(responseText,statusText){
model.trigger('saved',responseText);
},
error : function(error, dataObj, xhr) {
alert('Error');
}
});
}
}
这里查看保存的绑定方法,并在保存后触发该方法
this.model.on('saved',function(){
// do call back stuff
});
this.model.savePosition({data:{...}});
我们使用这种方法来冻结UI,直到执行ajax请求为止。我们在模型中添加了两个额外的事件冻结/解冻,分别在保存之前和从服务器收到应答之后触发。尝试覆盖“.sync()”方法。在覆盖传入的成功回调后,Backbone.save()将委托给Backbone.sync()。这就是模型更新的来源 从主干.save()方法的源: 您可以在调用“.save()”时传递一个自定义选项,然后在“.sync()”中查找该选项并重写options.success回调。也许是这样的
MyModel = Backbone.Model.extend({
sync: function (method, context, options) {
if (options.skipUpdateOnResponse) {
options.success = myCusomSuccessFunction;
}
}
});
myModel = new MyModel();
myModel.save({...}, {skipUpdateOnResponse: true})
服务器响应的属性是什么?主干网使用的默认成功回调执行以下操作:
if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) { ... }
按照此逻辑,如果服务器不返回对象,则不应在模型上调用set
或者,如果修改服务器响应,使其不返回传入的位置信息(这是问题的根本原因,并且在不了解您的要求的情况下,也似乎有点多余),则在调用set
时,不应覆盖这些属性
如果不使用这些选项,则按照@Uselessinfo的建议覆盖
sync
,或者在parse
中使用一些技巧可能是您的下一个最佳选择。在模型上使用验证方法:
validate: function(attrs) {
var errors = [];
if (attrs.position !== this.get('position')) {
errors.push('Outdated info!');
}
return _.any(errors) ? errors : null;
}
通过这种方式,您可以将服务器响应与模型中的现有数据进行比较。如果服务器响应与模型中的数据不同,则返回错误,并且不会调用set
方法。这可能需要save
方法选项中的wait:true
。使用这种方法,我认为您应该在执行实际保存之前在模型上设置位置
validate在保存之前调用,但如果{validate:true},也可以在set之前调用
主干存储成功回调:
options.success = function(resp, status, xhr) {
done = true;
var serverAttrs = model.parse(resp, xhr);
if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
if (!model.set(serverAttrs, options)) return false;
if (success) success(model, resp, options);
model.trigger('sync', model, resp, options);
};
因此,它在调用触发器“sync”和用户成功函数之前调用set allways。
并没有办法阻止你们们去做这件事,但有办法解决你们们的问题。
您可以通过以下方式覆盖模型中的“set”函数:
set: function() {
if (this.skipSetOperation()) return false;
return Backbone.Model.prototype.set.apply(this, arguments);
},
skipSetOperation: function() {
//this function should return stage - can model set attributes in this moment or not
}
希望有帮助。
Model.save
将调用Model.parse
对使用相同的options
参数接收的数据进行分析,然后再实际设置它
您可以调用Model.save
,并使用自定义标志(比如position:true
)指示Model.parse
可以放弃服务器返回的内容
例如,假设您的坐标是x
和y
var M = Backbone.Model.extend({
parse: function(data, options) {
if (options && options.position)
data = _.omit(data, 'x', 'y');
return data;
}
});
var m = new M();
m.save({x: 10, y:10}, {position: true});
m.save({x: 20, y:20}, {position: true});
还有一个演示我现在使用以下解决方案: 覆盖模型的默认分析方法:
Backbone.Model.prototype.parse = function(resp, options) {
if(options.parse)
return resp;
};
现在,您可以使用属性“parse”设置为false的save方法来防止ajax响应覆盖当前值:
MyModel.save({}, { parse: false });
谢谢你的建议,但是我没有将等待选项设置为true。问题是,如果返回的参数与当前模型上的参数不同,主干在服务器响应后将始终使用set方法。但这会影响所有保存操作,对吗?因为我不想破坏其他保存操作的功能。除非您覆盖
model.save
,否则在成功回调时调用abort
为时已晚,主干网自己的回调将被执行,因此您的模型已经设置了服务器属性。关于最初的问题…不幸的是没有,没有这样的选择。但是,最简单的方法是编写自己的服务器同步功能,并使用该功能而不是model.save
。您也可以仅为该特定模型覆盖save
。更具体的解决方案可能包括在模型内创建某种更新时间戳或版本计数器。验证或模型。解析您可以使用时间戳或计数器进行操作。您可以覆盖解析()
仅在特定型号上运行。我同意,在成功回拨时调用中止将为时已晚。我的意思是对圣
MyModel.save({}, { parse: false });