Backbone.ioBindのSyncで起こっていること(Model編)


以前の投稿では、Backbone標準のSyncについて調べてみましたが、今回は通信をAjaxではなくSocket.ioで行えるライブラリ、Backbone.ioBindについて使い方を調べてみました。

Backbone.iobind(Github)

結論から言うと、標準のSyncとほぼ同じ感じで使うことができます。WebSocktを使える環境の場合、Ajaxよりもオーバーヘッドが少ないので、小さいデータを頻繁に通信する場合は、こちらの方が有利だと思います。

前回の記事のプログラムをBackbone.ioBindで書くとこうなります。

 




・サーバー:app.js

var express = require('express')
, routes = require('./routes')
, http = require('http')
, path = require('path')
//単にsocket系のロジックを別ファイルにしたかっただけ。
, io = require('./lib/socket');

var app = express();

app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function(){
app.use(express.errorHandler());
});

app.locals.port = app.get('port');

app.get('/', routes.index);

var server = http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});

io.listen(server);


・サーバー:lib/socket.js
単にsocket系のロジックを別ファイルにしたかっただけ。 クライアントからのデータは全てここで処理します。

module.exports.listen = function(server){
var io = require('socket.io').listen(server);

io.sockets.on('connection', function (socket) {
console.log('connected');

socket.on('foo:create', function (data, callback) {
console.log('create: ',data);
// -> create: { hoge: 'hoge' }
if(callback) callback(null, {id: 0});
// エラーの場合はnullではなくerrオブジェクトを返す。
// 例: callback(err);
});

socket.on('foo:update', function (data, callback) {
console.log('update :',data);
// -> update : { hoge: 'hoge', id: 0, foo: 'foo' }
if(callback) callback(null, {});
});

socket.on('foo:read', function (data, callback) {
console.log('read: ', data);
// -> read: { hoge: 'hoge', id: 0, foo: 'foo' }
if(callback) callback(null, {'bar': 'bar'});
});

socket.on('foo:delete', function (data, callback) {
console.log('delete: ',data);
// -> delete: { hoge: 'hoge', id: 0, foo: 'foo', bar: 'bar' }
if(callback) callback(null, {});
});
});

return io;
};


・サーバー:view/index.jade
クライアントで読み込んでいるライブラリはこれだ!

doctype 5
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
script
//- localsにある値を全てJSファイル内で使えるようにする。
var locals = !{JSON.stringify(locals)};
body
h1= title
p Welcome to #{title}

script(src='/javascripts/jquery-1.9.1.min.js')
script(src='/javascripts/underscore-min.js')
script(src='/javascripts/backbone-min.js')
script(src='/socket.io/socket.io.js')
script(src='/javascripts/backbone.iosync.min.js')
script(src='/javascripts/backbone.iobind.min.js')
script(src='/javascripts/async.js')
script(src='/javascripts/client.js')


・クライアント:client.js

(function() {

var socket = io.connect(null, {port: locals.port});

var TestModel = Backbone.Model.extend({
urlRoot: 'foo',
socket: socket,
defaults:{
hoge: 'hoge'
}
});

var testModel = new TestModel();

// 非同期のものを順番に実行するためasync.jsを活用する。
async.series([

// POST(create)
function(callback){
testModel.save(null,{
// デフォルトと同様にsuccess、errorメソットが使える。
success: function(model, response, options){
console.log('success: ', model.toJSON());
// -> {hoge: "hoge", id: 0}

callback(null);
},
error: function(model, xhr, options){
// エラーの場合ここに処理を書く。
}
});
},

// PUT(update)
function(callback){
testModel.save({foo: 'foo'},{
success: function(model, response, options){
console.log('success: ', model.toJSON());
// -> {hoge: "hoge", id: 0, foo: "foo"}

callback(null);
}
});
},

// GET(read)
function(callback){
testModel.fetch({
success: function(model, response, options){
console.log('success: ', model.toJSON());
// -> {hoge: "hoge", id: 0,
// foo: "foo", bar: "bar"}

callback(null);
}
});
},

// DELETE(delete)
function(callback){
testModel.destroy({
success: function(model, response, options){
console.log('success: ', model.toJSON());
// -> {hoge: "hoge", id: 0,
// foo: "foo", bar: "bar"}

callback(null);
}
});
},

function(callback){
console.log(testModel);
// destroyしても消せません。。。
callback(null);
},
],
function(err, results){
if(err) console.log(err);
else console.log('Completed!');
});

})();


前回の記事と比べるとわかりますが、ほぼBakcbone.js標準のSyncと同じ感覚で使えますね。違うとすれば、socket.ioなのでサーバー側はreq.bodyやreq.paramsではデータを受信できません(当たり前か)。IDまで含めてdataに突っ込んで通信してきますので、そこをちょいと書き換えるだけで済むと思います。