一个用于多个视图的主干模型,谁处理 fetch()

One Backbone model for several views, who handles the fetch()?

本文关键字:模型 处理 fetch 视图 一个 用于      更新时间:2023-09-26

在多个视图之间共享主干模型是一种相当普遍的情况。尽管如此,假设这个模型是一个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() {
       …
    }
});

现在,如果我实例化HomeViewuserModel将被获取。但是,如果在以后的某个时候,我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(),在视图中是无状态的。

或者,我可以在视图层上处理它:

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的model.changed文档参考和Underscore的_.isEmpty

哪种方式更干净?还有其他我可能错过的方法吗?

个人偏好不是覆盖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调用自身...(,所以我个人的偏好是将核心主干功能包装在另一个函数中。

我什至会拥有自己的自定义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将用于某些/所有模型,以便可以适当修改。