Play框架与NodeJS的简单比较

Play框架是使用Iteratees, Enumerators, 和 Enumeratees之类抽象以一种函数式编程方式进行流处理,如Comet, chunked responses分块响应, WebSockets。

在Javascript那边, Node.js的socket.io是使用EventEmitter API通过命令式编程方法进行流处理。这个方法简单易学。

下面以一个案例,重点将放在WebSockets ,包括基本的“Hello World ”的例子,一个echo服务器,以及一个简单的聊天应用程序。

Producer生产者, consumer消费者, adapter适配器

Iteratee, Enumerator, 和 Enumeratee概念让人迷惑,让我们还是用人类概念来解释一下他们:

Enumerator: 实际就是生产者,这是发出数据块的地方。

Iteratee: 实际就是消费者。他们是Java迭代器的反转:在一个Iterator中你定义“next”是请求下一个数据块,在Iteratee中,你定义了一个“fold”方法,是对每个数据块做出反应react(控制反转)。

Enumeratee: 实际是Adapter适配器, Enumeratees可以附加在Iteratees前以便修改通过他们的流数据。

Hello World案例
开始一个hello world的websocket案例,首先你要监听socket, NodeJS的代码如下:


var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
console.log("Someone just connected!");
});

在Play框架中,你会创建一个WebSocket Action,然后返回Enumerator,它用来发送消息给客户端,还有 Iteratee 是用来对来自客户端的消息即时反应. 第一个版本返回Enumerator 和 Iteratee暂时什么都不做。


object Socket extends Controller {

def connect = WebSocket.using[String] { request =>
Logger.info("Someone just connected!")

// For this first example, we return an Iteratee and
// Enumerator that do nothing
(Iteratee.ignore, Enumerator.empty)
}
}

需要把这个端点配置在路由文件中:
GET /connect controllers.Socket.connect

现在你可以使用 ws://localhost:9000/连接了,连接客户端在http://www.websocket.org/echo.html

下面开始加入发送消息功能,在node.js增加了一行
/ Send a message to the client
socket.emit('message', "Hello!");

在Play框架中,我们创建Enumerato,可以从来自File, InputStream, OutputStream, a Future等来源创建它,这里只用一个固定数据集来创建它。


object Socket extends Controller {

def connect = WebSocket.using[String] { request =>
Logger.info("Someone just connected!")

// Create an Enumerator that sends a message to the
// client 创建Enumerator
val enumerator = Enumerator(
"Hello!")

(Iteratee.ignore, enumerator)
}
}

最后一个功能接受客户端的消息,在Node.js:


var io = require('socket.io').listen(80);

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

// Send a message to the client
socket.emit('message',
"Hello!");

// Listen for messages from the client
socket.on('message', function (message) {
console.log(
"Got message: " + message);
});
});

在Play框架中,我们必须创建一个Iteratee来监听来自客户端的消息。Iteratee有几个方法,“消费”(消费将所有的数据),“头”(消费的数据只是第一个块),和“foreach”,它为每个数据块提供触发一个回调。


object Socket extends Controller {

def connect = WebSocket.using[String] { request =>
Logger.info("Someone just connected!")

// Create an Enumerator that sends a message to the
// client
val enumerator = Enumerator(
"Hello!")

// Create an Iteratee that listens for messages from
// the client
val iteratee = Iteratee.foreach[String] { msg =>
Logger.info(s
"Got message $msg")
}

(iteratee, enumerator)
}
}


更深入案例见原文:
Play, Scala, and Iteratees vs. Node.js, JavaScript, and Socket.io