使用Backbone.js和Socket.IO构建Web应用程序

本文由Thomas GrecoMarc Towler进行了同行评审。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!

众所周知, Backbone.js是一个著名的MV *框架。 它托管在GitHub上,并通过提供具有键值绑定和自定义事件的模型,具有丰富的可枚举函数的API,具有声明性事件处理的视图的集合,并通过RESTful JSON将其全部连接到现有API,为Web应用程序提供结构接口。

在本文中,我们将使用称为事件的Backbone内置功能来实现异步消息传递范例,以避免耦合。 这个想法是将高度相互依赖的代码分开。

我将展示的示例是一个图形可视化工具 ,其中数据可以很好地跨用户同步。 WebSockets的使用将使打开用户浏览器和服务器之间的交互式通信会话成为可能。

目的是使示例尽可能简单。 此处学习的概念将有助于您减少耦合。 另外,这对于构建可扩展,灵活和可维护的代码是非常有用的方法。 在实验结束时,我们将得到以下结果:

图形可视化工具

Backbone.js

Backbone.js是一个通过提供模型视图控制器集合自定义事件来构建单页应用程序的框架。 它的结构帮助我们将用户界面与业务逻辑分开。 在本文中,我仅向您介绍其中一些元素,但是如果您需要更深入的指导,建议您阅读文章“ Backbone.js基础:模型,视图,集合和模板 ”。

模型代表数据,可以通过扩展Backbone.Model来创建它:

var MyModel = Backbone.Model.extend({
  initialize: function () {
    console.log('model initialized');
  }
})

视图是一种将用户界面组织成由模型支持的逻辑视图的方法。 它不包含HTML标记,而只是包含向用户呈现模型数据的逻辑。 要创建视图,您需要扩展Backbone.View ,如下所示:

var MyView = Backbone.View.extend({
  el: 'div#my-view-container',
  initialize: function (options) {
    this.model = new MyModel()
    console.log('view initialized')
  }
})

事件是可以混入任何对象的模块,使该对象能够绑定和触发自定义命名事件。 模型视图都有这个模块事件 ,允许我们将事件绑定到模型视图 。 一种常见的模式是创建可监听模型更改的视图。 该技术通常旨在允许视图在基础数据更改时自动重新呈现自己。

为了给您提供这些元素如何协同工作的示例,我在CodePen上创建了一个演示

请参阅CodePen上的SitePoint( @SitePoint )提供的Pen XXpwMQ

每当我们更改输入时视图都会更改我们的模型 。 按下“确定”按钮后,视图将呈现新的id值。

服务器与客户端之间的实时通信

WebSockets是一种高级方式,可以打开用户浏览器和服务器之间的交互式通信会话。 使用此API,用户可以将消息发送到服务器并接收事件驱动的响应,而不必轮询服务器以获取答复。 该合同是描述规则和预期行为的协议,需要双方采取行动。 当这两个部分通过API链接在一起时,它充当集成服务器和客户端的胶水

在桥梁类比中,一旦就位,数据和指令就可以越过桥梁。 例如,服务器接收一条指令,执行一个动作,然后在处理该指令后,它将信息返回给Web应用程序。 各方之间的互惠互利。 使用此抽象层(API) ,我们可以隐藏Web服务的复杂内容,而无需了解有关服务器如何执行操作的更多详细信息。

Socket.IO是一个用于实时Web应用程序的JavaScript库。 它支持Web客户端和服务器之间的双向通信。 双方具有相同的API,并且像Node.js一样受事件驱动。 要打开浏览器和服务器之间的交互式通信会话,我们必须创建一个HTTP服务器以启用实时通信。 这将使我们能够发出和接收消息。 socket是处理Web客户端和服务器之间此通信的对象。

下面的代码使用带有Express框架的 socket.IO创建该服务器。

var express = require('express'),  
    app     = express(),
    http    = require('http').Server(app),
    io      = require('socket.io')(http);

http.listen(process.env.PORT || 5000, function(){  
  console.log('listening on *:5000');
});

创建该服务器后,我们将拥有io类,该类允许设置一个以socket为参数的回调。 使用此socket对象,我们可以在用户的​​浏览器和服务器之间创建连接。

io.on('connection', function(socket) {  
  console.log('a user connected');
  socket.on('disconnect', function(){
    console.log('user disconnected');
  });
});

在浏览器中,客户端链接到服务器,调用io函数,该函数返回用于连接的socket

var socket = io("http://pubsub-example-with-backbone.herokuapp.com/");

话虽如此,让我们创建一个简单的通信,使数据和指令可以跨越网桥。

var socket = io("http://pubsub-example-with-backbone.herokuapp.com/")

// retrieve all nodes already stored in the server
socket.emit('retrieve-all-nodes')

$("button#add-new-node")
  .on('click', function () {
    socket.emit('add-node', {}, function (obj) {
      console.log(obj)
    })
  })

socket.on('node-added', function (node) {
  var $nodes = $("ul#nodes").append(`
    <li id="${node.id}">
      <span>${node.id}</span>
      <button>x</button>
    </li>
  `)

  $nodes
    .find(`li#${node.id} button`)
    .on('click', function () {
      socket.emit('remove-node', node)
    })
})

socket.on('node-removed', function (node) {
  $("ul#nodes").find(`#${node.id}`).remove()
})

有了此代码,我们就可以构建以下演示

请参阅CodePen上的SitePoint( @SitePoint )的Pen mVRYMW

如果您想了解有关Socket.IO和Express的更多信息,建议您阅读以下文章:

Backbone.js与Socket.IO

在本节中我将告诉你一个例子说明如何使用Socket.IO与Backbone.js的:

var MyView = Backbone.View.extend({
  el: '#my-backbone-app',
  events: {
    'click button#add-new-node': 'addNewNode'
  },
  initialize: function (options) {
    var view = this
    view.socket = io("http://pubsub-example-with-backbone.herokuapp.com/")
    view.socket.emit('retrieve-all-nodes')
    view.model = new MyModel()

    view.socket.on('node-added', function (node) {
      var $node = $(`
        <li>
          <span>${node.id}</span>
          <button>x</button>
        </li>
      `)
      view.model.set(node.id, $node)

      view.$el.find("ul#nodes").append($node)
      $node.on('click', function () {
        view.socket.emit('remove-node', node)
      })
    })

    view.socket.on('node-removed', function (node) {
      view.model.get(node.id).remove()
      view.model.unset(node.id, {})
    })
    console.log('view initialized')
  },

  addNewNode: function () {
    this.socket.emit('add-node', {}, function (obj) {
      console.log(obj)
    })
  }
})

结果如下:

请参阅CodePen上的SitePoint( @SitePoint )提供的Pen QydXwo

带Backbone.js的PubSub

PubSub是异步消息传递范例。 它提供的功能可避免耦合。 耦合是指一组代码彼此高度依赖时,这意味着如果一段代码发生更改,则需要对使用该段代码的所有内容进行更新。

PubSub是具有同步解耦的模式。 它使用一种事件系统,就像广播的工作方式一样:广播电台广播( 发布 ),任何人都可以收听( 订阅 )。 此外,您可以直接在共享的广播电台上发布消息,而不必直接与其他对象交谈。 该事件系统允许我们定义事件,这些事件可以传递包含订户所需值的参数。 Backbone.js使此事件系统的实现非常简单。 您只需要通过以下方式将Backbone.Events混合到一个空对象中:

var EventChannel = _.extend({}, Backbone.Events);

此时,您可以使用标准triggeron方法来发布和订阅消息:

var socket = io("http://pubsub-example-with-backbone.herokuapp.com/")

var MyPubSub = $.extend({}, Backbone.Events)
MyPubSub.on('disconnect', function () {
  console.warn('disconnected')
})

socket.on('node-added', function (node) {
  MyPubSub.trigger('node-added', node)
})

socket.on('node-removed', function (node) {
  MyPubSub.trigger('node-removed', node)
})

MyPubSub.on('retrieve-all-nodes', function () {
  socket.emit('retrieve-all-nodes')
})

MyPubSub.on('add-node', function (node, cb) {
  socket.emit('add-node', node, function (obj) {
    if (cb) {
      node.id = obj.id
      cb(node)
    }
  })
})

MyPubSub.on('remove-node', function (node) {
  if (node && node.id) {
    socket.emit('remove-node', node)
  }
})

这样,您现在就可以从我们的Backbone View中删除socket.io

var MyView = Backbone.View.extend({
  el: '#my-backbone-app',
  events: {
    'click button#add-new-node': 'addNewNode'
  },
  initialize: function (options) {
    var view = this
    view.model = new MyModel()

    MyPubSub.on('node-added', function (node) {
      var $node = $(`
        <li>
          <span>${node.id}</span>
          <button>x</button>
        </li>
      `)
      view.model.set(node.id, $node)

      view.$el.find("ul#nodes").append($node)
      $node.on('click', function () {
        MyPubSub.trigger('remove-node', node)
      })
    })

    MyPubSub.on('node-removed', function (node) {
      view.model.get(node.id).remove()
      view.model.unset(node.id, {})
    })

    MyPubSub.trigger('retrieve-all-nodes')
    console.log('view initialized')
  },

  addNewNode: function () {
    MyPubSub.trigger('add-node', {}, function (obj) {
      console.log(obj)
    })
  }
})

目的是避免模块之间的依赖性。 每个模块都可以有一个频道,例如广播事件的广播电台(发布者),其他任何模块都可以收听希望接收通知的事件(订阅者)。

获得的结果如下:

请参阅CodePen上的SitePoint( @SitePoint )的Pen gPgNpz

图形可视化示例

我们的图形可视化在客户端使用两个模块:一个用于绘制有向图,另一个用于存储和获取数据。 图形绘制模块使用名为Force Editor的工具。 该模块在代码中称为ForceView ,可让我们以简单直观的方式将图形的节点定位在二维空间中。 我们称为DBaaS的存储模块使用Socket.IO启用Web客户端和服务器之间的实时双向通信。 他们, ForceViewDBaaS都不了解其他任何东西。 他们的行为都是孤立的。

这两个模块都以发布/订阅样式设置,以避免依赖。 他们使用事件系统的方式与广播工作相同,广播站广播(发布),无线电接收器收听(订阅)。 每个模块都可以在自己的频道上触发事件,而不是直接与其他模块交谈,而是将消息发布在共享的“ 广播电台 ”上,而另一个模块也可以侦听其他任何频道上的事件。

这里唯一的依赖关系是每个具有非常小的API的无线电信道。 重要的是通道触发了哪个消息,并确保系统对事件做出正确的反应。 如果他们触发事件并给出正确的信息,则系统将整体运行。 查看下面的图像,以查看这些模块中的每个模块正在发出哪些事件。

dbaas模块

强制查看模块

骨干视图充当ForceView和DBaaS之间的中介。 这使我们可以将所有内容分解为可用的小片段,然后使这些小片段完美地协同工作。 这样,代码变得更易于理解和易于维护。

例如,如果我们只想对它进行一点自定义以使其适合特定的口味,则我们可以轻松地选择任何模块并以我们喜欢的任何方式对其进行更改。 我们可以用其他图形库代替图形可视化,例如jqPlotDraculaArborJSsigmajsRaphaelJS 等等 。 或者我们可以使用任何实时数据库,例如FirebaseAppbaseNeo4jTitanDB等。好消息是我们只需要更改一个文件即可迁移到另一个库。 下图说明了骨干视图与这两个模块之间的交互。

请注意,我们没有使用任何数据库。 数据正在存储在内存中。 解耦代码的方式允许我们连接到任何类型的数据库。

PubSub作为广播电台

在本地运行图可视化示例

完整代码可在GitHub上获得 。 您可以克隆存储库或下载代码

git clone https: //github.com/sitepoint-editors/pubsub-example-with-backbone.git

然后从控制台执行npm install以安装所有依赖项。

接下来,执行node server.js以启动应用程序。

使用浏览器访问http:// localhost:5000以查看正在运行的应用程序。 如果您只想查看实际的应用程序,可以在此处找到一个演示

结论

完蛋了! 我们只是使用Backbone的内置功能来实现PubSub模式。 此外,我们使用此模式实时表示和存储图形数据,其中数据在用户之间进行了精美的同步。 如您所见,在一个很好的示例中,我们混合了一些有趣的概念,以查看解耦的代码段协同工作。

现在的下一步是对其进行自定义,并将数据存储在数据库中,而不是存储在内存中。 但是我们可能会在即将发表的一篇文章中讨论有关定制的问题。

请在下面的部分中随意分享您的评论。

From: https://www.sitepoint.com/build-a-web-app-with-backbone-js-and-socket-io/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值