javascript - 一个 Backbone 模型用于多个 View ,谁处理 fetch()?

标签 javascript backbone.js model synchronization

在多个 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) {
        …
    }
});

现在假设它由双方共享:

HomeViewCartView

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/

相关文章:

r - R 中两个模型的 f 检验

javascript - 在 Chrome 中获取伪元素内容

javascript - 使用 jQuery 将元素名称分配给多个元素的名称作为前缀

javascript - 如何使用数据数组来制作选定的复选框?

javascript - 当我使用 Backbone 和 AMD 模块时,存储授权数据的最佳位置在哪里?

javascript - 使用 BackboneJS 从 subview 调用 View 函数

javascript - 关闭网站选项卡时如何向 Chrome 发送通知?

javascript - Backbone : Create collection from JSON

javascript - 如何在 JavaScript 中加载文本文件?

c# - 使用自定义属性和模型打开 asp.net mvc 窗口