一个用于处理fetch()的几个视图的Backbone模型?

时间:2016-11-15 23:34:58

标签: javascript backbone.js model synchronization

在多个视图之间共享Backbone模型是一种相当常见的情况。不过,我们假设这个模型是UserModel。它处理多种方法,允许用户注册或登录。

当用户被记录时,调用fetch来获取用户的数据。因此,模型无法在this.fetch()方法中使用initialize获取自身。

从哪里拿出来的?怎么样?

这是我们的简单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方法后获取,但用户可以到达页面或重新加载已登录的浏览器。此外,用户可以登陆任何页面,那里和#39;无法说他在HomeView之前前往CartView

我看到有两种选择。 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&下划线的_.isEmpty's

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

1 个答案:

答案 0 :(得分:3)

个人偏好不会覆盖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会在某些/所有模型中使用,因此可以适当修改。