2012年10月23日 星期二

jsdx-power 讓你使用 JavaScript 實現電源管理

Standard
既然會成立新創公司,總有些自己的想法,也期望做一些和其他人不一樣的事,對我們而言,改變世界事小,留下長久價值更重要。也許你有點印象,筆者今年度到處給予的 Talk,多半都是與 Node.js 相關,也透漏許多正在執行的計劃。因此,有些人可能聽過筆者提及『JSDX Framework』,這是『Mandice』的長期計劃,也是將 JavaScript 落實在系統、桌面和嵌入式裝置的解決方案。

由於 JSDX 是一個開放原始碼專案,市場上也已經有一些產品和公司專案導入使用,但因為合約的關係,我不能透漏太多細節,所以本文將只討論些許技術細節。說到這,也許你還是沒什麼概念,但若是真要舉出最直接與其相關的專案,就是今年 8 月,於 COSCUP 一場議程中所公開的『JUICE Desktop Environment』(簡報檔詳見舊文:【COSCUP 2012】閉幕!簡報釋出!),完全以 JavaScript 實作的 3D 桌面環境。

JSDX 包括許多元件,從 GUI Toolkit(使用者界面)、Multimedia Player(多媒體播放)、Network Manager(網路管理)到 Sound Manager(聲音管理)等,提供了各類系統控制或硬體相關的 APIs。程式開發者只需要會 JavaScript 語言,就可以使用這些 JSDX 所提供的 APIs ,開發各類應用程式或系統程式。

回應本文標題,JSDX 如果可以拿來開發桌面環境,當然也有電源管理相關的 APIs 可使用。所以在這邊我們要討論的元件是『jsdx-power』,你可以在 github 上取的他的 Source Code,亦或是直接透過 npm 安裝。
npm install jsdx-power

這邊簡單示範如何使用 JavaScript 透過『jsdx-power』命令作業系統休眠:
var Power = require('jsdx-power');

var power = new Power;

power.init(function() {
 power.suspend();
});

後記

JUICE DE 的 juice-panel 電量顯示,就是使用了 jsdx-power,有興趣的人可以參考其 Source Code。

2012年10月8日 星期一

Node.js 裡的 JavaScript Array 非同步操作

Standard
如果你原本是一個專業的前端工程師,或許在 Node.js 出來之後,便開始嘗試了 Server 程式的開發。然後發現,使用 JavaScript 開發 Server 程式的過程中,有很多的細節應該注意,尤其是碰上處理大量資料和 I/O 操作時,更要對 JavaScript 引擎的運作原理有一定程度的理解。因為,絕大多數的問題,都是出在非同步(Asynchronize)與同步(Synchronize)的機制上。

許多開發人員,都會認同在開發 Node.js 程式時,盡可能、甚至絕對不要使用『同步』的方法和 API,因為,那會打亂 JavaScript 事件引擎的運作,產生各種詭異的後疑症,而且非常難以除錯。如果你發現你的程式會莫明自己結束,或是程式運作的流程不如預期,可能就是掉入了『同步』與『非同步』的陷阱了。

如果你稍微翻過文件,就會發現,其實 Node.js 本身對很多的 API,已經同時提供了『同步』與『非同步』兩種版本供開發者使用。不過,雖然 Node.js API 都有提供『非同步』版本,但是有些根本東西,卻欠缺『非同步』的方法,像是本文標題所提到的『Array』,就是其中之一。

針對 Array 的諸多操作,最常見的莫過於 forEach 方法,用來處理每一個 Array item:
var arr = [ 1, 2, 3, 4 ];

arr.forEach(function(element, index, arr) {
    // Processing
});

console.log('Completed');
然而,這個方法是『同步(Synchronize)』,也就是會讓整個程式阻塞,等所有 Array item 讀出和處理完之後,才顯示最後的『Completed』字串。

類似的東西,不少人也會使用純 for-loop 來實作,但也都是一樣的狀況:
var arr = [ 1, 2, 3, 4 ];

for (var i in arr) {
    // Processing
}

console.log('Completed');

想想看,如果 Array item 的數量相當多,又或者是每個 item 的處理時間相當長,整支程式會像死當一樣沒反應。要知道,讓一段程式跑太久,是 Event-driven 的忌諱,更是 Server 程式的大敵,因為它會讓你的網站服務反應速度極慢。可是,這樣操作 Array 資料的需求,卻又是非常常見。

還好,多數人開始學習 Node.js 之後,因為對 Event-driven 的機制開始越來越熟悉,所以,開始能夠瞭解並利用各種非同步的方法,讓程式避免阻塞死鎖,增加效能和處理更多的連線要求。也因為如此,針對 Array 的遍歷操作,自然懂得開始使用遞迴的方式處理。但是,這樣常見的用法,時時都會出現,每次都要重新實作一次,豈不麻煩?

尋思,我們是否可以有個簡單的做法,以『非同步(Asynchronize)』的方法去操作 Array 呢?

當然,筆者自認是世界上最懶惰的人,所以,就為此開發出『node-array』,讓日後能少打點字:
https://github.com/cfsghost/node-array

安裝方法相當簡單,你可以直接從 NPM 上安裝:
npm install node-array

使用方法更簡單,node-array 提供了一個新的方法『forEachAsync()』,如 Array 原生的 forEach 一樣使用即可:
var Array = require('node-array');
    
var a = [ 1, 2, 3, 4, 5 ];
    
a.forEachAsync(function(element, index, arr) {
    console.log(element);
}, function() {
    console.log('complete');
});

從上面的程式碼可以知道,其實 node-array 是幫原生的 JavaScript Array Object 擴充功能,繼承了原生的 Array Object,並添加了一個新的方法進去。所以,你一但在開頭將 Array 用 node-array 取代掉,之後所有建立的 Array Object 都能有 forEachAsync() 方法可使用。從此,你不用再花心力去搞定遞迴和 process.nextTick() 了!

最後一提,node-array 初步只實作了最常用到的 forEach,日後也陸續會將其他常用的功能加入。如果您有什麼想法或 patch,歡迎提交給小弟。:-)

後記

解決了這類根本的問題後,並應用在實際開發後,意外發現了一個正面的副作用,就是程式碼漂亮很多,也『平坦』許多。讓我不禁思考,很多想把 JavaScript 程式碼平坦化的工作,是否真的必要?若是所有根本性的問題解決後,是否程式碼自然就不會太高聳?