在多个 View 之间共享 Backbone 模型是一种相当常见的情况。尽管如此,我们还是假设这个模型是一个UserModel
。它处理多种方法,例如允许用户注册或登录。
当用户登录时,会调用 fetch 来获取用户的数据。因此,模型无法在其 initialize
方法中使用 this.fetch()
获取自身。
应该从哪里获取?怎么办?
这是我们简单的UserModel
:
const UserModel = Backbone.Model.extend({
// get url for 'me' (ie connected user)
url() {
return app.endpoint + '/users/me/' + app.conToken;
},
login(email, password, rememberMe, callback) {
…
},
signup(email, password, firstname, lastname, callback) {
…
}
});
现在假设它由双方共享:
HomeView
和 CartView
app.HomeView = Backbone.View.extend({
template: app.tpl.home,
initialize() {
// model is passed @ instanciation
this.model.fetch();
this.listenTo(this.model, 'sync', this.render);
},
render() {
…
}
});
app.CartView = Backbone.View.extend({
template: app.tpl.cart,
initialize() {
// model is passed @ instanciation
this.model.fetch();
this.listenTo(this.model, 'sync', this.render);
},
render() {
…
}
});
现在,如果我实例化 HomeView
,将获取 userModel
。但是,如果稍后我实例化 CartView
,则会再次获取相同的模型。这会产生一个无用的 http 请求。
基本上,模型可以在成功调用其 login
方法后获取 istself,但用户可以到达页面或重新加载已登录的浏览器。此外,用户可以登陆任何页面,没有办法说他会在 CartView
之前访问 HomeView
。
我看到有两个选项。 UserModel
可以智能地处理多个 fetch
调用,如下所示:
const UserModel = Backbone.Model.extend({
// get url for 'me' (ie connected user)
url() {
return app.endpoint + '/users/me/' + app.conToken;
},
isSync() {
// an hour ago
let hourAgo = Date.now() - 3600000;
// data has been fetched less than an hour ago
if (this.fetchTime && hourAgo > this.fetchTime) return true;
return false;
},
fetch() {
// has not already fetched data or data is older than an hour
if (!this.isSync()) {
this.fetchTime = Date.now();
this.fetch();
return;
}
// trigger sync without issuing any http call
this.trigger('sync');
},
…
});
这样,我就可以根据需要多次调用 this.model.fetch()
,并且在 View 中保持无状态。
或者,我可以在 View 层上处理它:
app.HomeView = Backbone.View.extend({
template: app.tpl.home,
initialize() {
// model is passed @ instanciation
// fetch model if empty
if (_.isEmpty(this.model.changed)) this.fetch();
// render directly if already populated
else this.render();
// render on model sync
this.listenTo(this.model, 'sync', this.render);
},
render() {
…
}
});
如果需要,Backbone's model.changed
文档引用和下划线的 _.isEmpty
's .
哪种方式更干净?还有其他我可能错过的方法吗?
最佳答案
个人偏好不是重写fetch
,而是实现一个包装函数,例如customFetch
const UserModel = Backbone.Model.extend({
// get url for 'me' (ie connected user)
url() {
return app.endpoint + '/users/me/' + app.conToken;
},
isSync() {
// an hour ago
let hourAgo = Date.now() - 3600000;
// data has been fetched less than an hour ago
if (this.fetchTime && hourAgo > this.fetchTime) return true;
return false;
},
customFetch() {
// has not already fetched data or data is older than an hour
if (!this.isSync()) {
this.fetchTime = Date.now();
this.fetch();
return;
}
// trigger sync without issuing any http call
this.trigger('sync');
},
…
});
您提供的代码示例最终会陷入循环(this.fetch
调用自身...),因此我个人的偏好是将核心主干功能包装在另一个函数中。
我什至会拥有自己的自定义模型
,它可以由我使用的所有模型进行扩展。例如:
const MyModel = Backbone.Model.extend({
isSync() {
// an hour ago
let hourAgo = Date.now() - 3600000;
// data has been fetched less than an hour ago
return (this.fetchTime && hourAgo > this.fetchTime);
},
customFetch() {
this.fetch();
},
});
然后UserModel
将覆盖customFetch
并且看起来像这样:
const UserModel = MyModel.extend({
customFetch() {
// has not already fetched data or data is older than an hour
if (!this.isSync()) {
this.fetchTime = Date.now();
this.fetch();
return;
}
// trigger sync without issuing any http call
this.trigger('sync');
},
});
可能不是最好的方法。对我个人而言,这将是阅读和稍后扩展的简单方法。我想这个 customFetch
将在某些/所有模型中使用,因此可以适当修改。
关于javascript - 一个 Backbone 模型用于多个 View ,谁处理 fetch()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40621618/