目前,web应用普遍被要求是实时web应用,即服务端的数据更新之后,应用能立即更新。以前使用的技术(例如polling)存在一些局限性,而且有时我们需要在客户端打开一个socket,然后进行通信。
Socket.IO(http://socket.io/)是一个非常优秀的库,它可以帮你实现以上功能。它使用了非常简单的、基于事件的API,让你可以开发实时web应用。我们打算开发一个实时的匿名广播系统(类似于Twitter,只是我们的系统没有用户名),它可以向Socket.IO上的所有用户发送消息,并且自已也可以看到所有消息。系统不会存储任何东西,所以只有当用户处于活动状态时消息才是存活的,但是这个例子足以说明Socket.IO可以和AngularJS完美地集成到一起。
稍后,我们将会把Socket.IO包装到一个很好的AngularJS服务中去,这样我们可以保证:
1.Socket.IO的事件将会在AngularJS生命周期内部进行通知并处理。
2.以后的集成测试会更加容易
app.js
var app = angular.module('myApp', []); //我们把socket服务定义成了一个factory,这样它只会被实例化一次,而且在整个应用的作用域范围内就成为了一个单例 app.factory('socket', function($rootScope) { var socket = io.connection('http://localhost:8899'); return { on: function(eventName, callback) { socket.on(eventName, function() { var args = arguments; $rootScope.$apply(function() { callback.apply(socket, args); }); }); }, emit: function(eventName, data, callback) { socket.emit(eventName, data, function() { var args = arguments; $rootScope.$apply(function() { if(callback) { callback.apply(socket, args); } }); }) } }; }); app.controller('MainCtrl', function($scope, socket) { $scope.message = ''; $scope.messages = []; //当我们看到一条从服务端发送过来的新消息时 socket.on('new:msg',function(message) { $scope.message.push(message); }); //告诉服务端有一条新消息 $scope.boradcast = function() { socket.emit('broadcast:msg', {message:$scope.message}); $scope.message.push($scope.message); $scope.message = ''; }; });
我们只包装了我们所关心的两个函数,它们是Socket.IO API里面on event和broadcast event方法。除此之外还有很多方法,都可以使用类似的方式进行包装。
控制器MainCtrl本身非常简单,它会监听socket连接上的一些事件,并且会监听用户是否按下了broadcast按钮,一旦按下就告诉服务器出现了一条新信息。它同时还会把消息添加到列表中,并立即显示给用户。
我们将会使用一个很简单的index.html,其中会显示一个带有发送按钮的文本框以及一个消息列表。在这个例子中,我们不会跟踪谁发送了消息,或者他们何时发送了消息。
index.html
<!DOCTYPE html> <html ng-app="myApp"> <head lang="en"> <meta charset="utf-8"></meta> <title>Anonymous Broadcaster</title> <script src="node_modules/socket.io/index.js"></script> <script src="angular/angular.js"></script> <script src="app.js"></script> </head> <body ng-controller="MainCtrl"> <input type="text" ng-model="message"></input> <button ng-click="broadcast()">Broadcast</button> <ul> <li ng-repeat="msg in message">{{msg}}</li> </ul> </body> </html>
最后就只剩下服务端了。这是一个NodeJS服务器,它知道如何为应用代码提供服务,并且还创建了一个模拟的Socket.IO服务器。
var app = require('express')(), server = require('http').createServer(app), io = require('socket.io').listen(server); server.listen(8899); app.get('/',function(req,res) { res.send/File(__dirname + '/index.html'); }); app.get('/app.js', function(req, res) { res.sendFile(__dirname + '/app.js'); }); io.sockets.on('connection', function(socket) { socket.emit('new:msg', 'Welcome to AnonBoard'); socket.on('broadcast:msg', function(data) { //把新的消息通知给所有其他客户端(除自已外) socket.broadcast.emit('new:msg', data.message); }); });
你可以很轻松地扩展它,用来处理更多信息和更加复杂的结构。这个例子打下了一个很好的基础,你可以利用它在你的客户端和服务端之间实现socket通信。
这个应用非常简单,它没有做任何校验操作(例如消息是否为空),但是它带有AngularJS默认提供的HTML清理功能。它不会处理复杂的消息,但是它提供了一个可运行端到端Socket.IO实现,并且集成到了AngularJS中,你可以基于此来构建自已的应用。