Rhino是基于Java的JavaScript解析器,實現了通過JavaScript程序訪問整個JavaAPI,Node是Google的V8 JavaScript解析器的一個特別版本,它在底層綁定了POSIXAPI,包括文件、進程、流和套接字,并側重于異步I/O、網絡和HTTP。
用Rhino腳本化Java
Rhino是一種用java編寫的JavaScript解釋器,Rhino能自動完成JavaScript原生類型與Java原生類型之間的相互轉換。
Rhino定義的全局函數:
- print(x); //全局輸出函數,將內容輸出到控制臺
- version(170); //告訴Rhino需要使用JS 1.7的語言特性
- load(filename,...); //加載并執行1個或多個JavaScript代碼文件
- readFile(file); //讀取文本文件,并以字符串的形式返回內容
- readUrl(url); //讀取URL的原文內容,并以字符串的形式返回內容
- spawn(f); //運行f()或者在一個新線程中加載執行文件f
- runCommand(cmd,[args...]); //使用O或多個命令行參數來運行系統命令
- quit(); //退出Rhino
Rhino會將Java包和類表示成JavaScript對象,因此可以將他們賦值給變量從而得到相應的短名:
var ArrayList = java.util.ArrayList; //為類創建短名
importClass(java.util.HashMap); //其等同于:var HashMap = java.util.HashMap
Java類能使用new進行實例化,就像JavaScript類一樣:
var f = new java.io.file("/tmp/test");
var out = new java.io.FileWiter(f);
Rhino讓JavaScript的instanceof運算符能用于Java對象和類:
f instanceof java.io.file; //true
out instanceof java.io.reader //false:他是writer而非Reader
out instanceof java.io.Vloseable //true:Writer實現Closeable
- Rhino也允許JavaScript代碼查詢、設置Java類的靜態字段和Java對象的實例字段。Java類通常利用getter和setter方法避免定義公共字段。
- 使用for/in循環遍歷Java類和對象的方法、字段和屬性,但是不能枚舉包中的類。
Java編程經常涉及實現接口,每個事件處理程序都必須實現事件監聽接口:
//用同樣的方式擴展抽象類
//當接口只有一個方法,可以使用一個函數取而代之
//如果需要一個對象實現多重接口,則使用JavaAdapter
Rhino會俺需要自動轉換為原始數字、布爾值和null。
用Node實現異步I/O
Node是基于C++的告訴JavaScript解釋器,綁定了用于進程、文件和網絡套接字底層的Unix API,還綁定了HTTP客戶端和服務器API。
由于API是異步的,因此Node依賴時間處理程序,其通常使用嵌套函數和閉包來實現 。
Node重要函數:
console.log() //調試輸出到控制臺
require()(相當于Rhino里的load()) //加載模塊,并返回其API對象
Node在process名字空間中定義了其他重要的全局屬性:
- process.version //Node的版本字符串信息
- process.argv //"node"命令行的數組參數,argv[0]是“node”;
- process.env //環境變量對象 例如:process.env.PATH
- process.pid //進程id
- process.getuid() //返回用戶id
- process.cwd() //返回當前的工作目錄
- process.chdir() //改變目錄
- process.exit() //退出(運行shutdown命令之后)
由于Node的函數和方法都是異步的,因此當他們等待運算完成時并不產生阻塞。非阻塞方法的返回值無法返回異步運算的結果。
如果想要獲取結果,就必須提供一個Node能夠調用的一個函數,在某些情況下,只需簡單的把函數作為參數傳遞,Node會適時調用它,在另外一些情況下,可以利用Node的事件機制。
Node對象產生事件,定義on()方法來注冊處理程序,當傳入參數時,將時間類型作為第一個參數,處理程序函數作為第二參數。
不同的時間類型傳遞給處理程序函數的參數不同:
- emitter.on(nama,f) //emitter注冊f函數處理name事件
- emitter.addListener(nama,f) //addListener()和on()是用一個方法
- emitter.once(name,f) //只執行一次,然后f會自動刪除
- emitter.listeners(name) //返回時間處理函數組成的數組
- emitter.removeListener(name,f) // 注銷事件處理程序f
- emitter.removeAllListeners(name) //移除name事件的所有處理程序
舉例:
//"exit"事件在Node退出之前發送
process.on("exit",function() { console.log("Goodbye"); });
Node的設計目標是高性能I/O,因此其流API常被用到。
從文件和網絡套接字中得到流對象:
//輸入流
- s.on("data",f); //當數據可用時,把它作為參數傳給f()
- s.on("end",f); //當不在有數據達到,在文件結束(EOF)時會觸發"end"事件
- s.on("error",f); //如果發生錯誤,把異常傳給f()
- s.readable //如果他是依舊打開的可讀流,返回true
- s.pause(); //暫停"data"時間,例如:為了限制上傳
- s.resume(); //再次恢復
//如果想把字符串傳給"data"事件處理程序,請指定編碼
- s.setEncoding(enc) //如何對字節編碼:"utf8"、"ascii"或"base64"
可寫流比可讀流的的核心事件少,使用write()方法發送數據,當所有數據寫入完畢后使用end()方法結束流。write方法不會阻塞,若Node方法無法立即寫入數據而不得不在內部緩存它,則write()返回false.
注冊"drain"事件的處理程序:
//輸出流
- s.write(buffer); //寫入二進制數據
- s.write(string,encoding) //寫入字符串數據,默認編碼是"utf-8"
- s.end() //結束流
- s.end(buffer); //寫入最后的二進制數據塊并結束
- s.end(str,encoding) //寫入最后的字符串并結束所有流
- s.writeable; //如果流依舊打開且可寫入,返回TRUE
- s.on("drain",f) // 當內部緩沖區為空,調用f()