多个视图的一个 Backbone 模型,谁处理 fetch()?
One Backbone model for several views, who handles the fetch()?
在多个视图之间共享一个 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
方法后自行获取,但用户可以到达页面或重新加载已经登录的浏览器。此外,用户可以登陆任何页面,没有办法说他会在 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()
,在视图中是无状态的。
或者,我可以在视图层上处理:
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
doc reference & Underscore's _.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
调用自身...),因此我个人的偏好是将核心 backbone 功能包装在另一个函数中。
我什至会拥有自己的自定义 Model
,它由我使用的所有模型扩展。例如:
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
会用在 some/all 模型中,所以它可以适当修改。
在多个视图之间共享一个 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
方法后自行获取,但用户可以到达页面或重新加载已经登录的浏览器。此外,用户可以登陆任何页面,没有办法说他会在 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()
,在视图中是无状态的。
或者,我可以在视图层上处理:
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
doc reference & Underscore's _.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
调用自身...),因此我个人的偏好是将核心 backbone 功能包装在另一个函数中。
我什至会拥有自己的自定义 Model
,它由我使用的所有模型扩展。例如:
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
会用在 some/all 模型中,所以它可以适当修改。