Play框架與NodeJS的簡單比較

banq發表於2013-11-26

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!");
});
<p>

在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)
  }
}
<p>

需要把這個端點配置在路由檔案中:

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)
  }
}
<p>

最後一個功能接受客戶端的訊息,在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);
  });  
});
<p>

在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)
  }
}
<p>

更深入案例見原文:

Play, Scala, and Iteratees vs. Node.js, JavaScript, and Socket.io

相關文章