io.js 的 ES6 Collection 支援 - Set

2015年1月29日 星期四
io.js 不做任何設定下,預設支援了一些 ECMAScript 6 的語法,其中包括一系列的 Collection 支援,這讓 JavaScript 在資料操作上多了一些方便之處。本文將討論到的 Set 物件,就是其中一個 Collection 類別。

簡單來說,Set 是一個類似 Array 的物件型態,可以用於處理有序的資料,而且內建迭代器(Iterator:在某些應用上同樣功能也會稱之游標 Cursor),讓開發者可以很容易對資料進行一筆筆的處理。

基本操作

基本的 Set 物件使用很簡單,如下所示:
// 建立一個新的 Set
var items = new Set();

// 依序加入資料
items.add('Fred');
items.add('Stacy');
items.add('Wesley');
items.add('Rance');
items.add('Kevin');
items.add('Alex');

// 依序印出 Set 物件內的所有資料
for (var item of items) {
    console.log(item);
}
比較特別的是,如果要依序印出 Set 物件內的所有資料,需要使用『of』這個關鍵字。原因是 Set 物件本身是一個 Generator 實作所致,如果我們想要一次把 Generator 內的工作跑完,需要運用 for-loop 加上 of 關鍵字來達成。

註:關於 Generator 與 of 關鍵字,日後有空再撰文說明其細節。總之,只要記得必須使用 of 關鍵字才能一一讀取 Set 物件內的資料,就像 Array 的 for-loop 加上 in 關鍵字。

刪除資料

刪除特定資料可以使用 remove() 方法來達成,如下所示:
items.remove('Wesley');
若是要清空資料,可以使用 clear() 方法:
items.clear();

檢查資料是否存在

我們可以直接利用 has() 方法檢查特定資料是否存在:
items.has('Rance');

迭代器(Iterator)的使用

Set 的迭代器是圍繞著 Generator 來實作,所以當我們想要利用 Set 的迭代器,可以使用 values() 方法來取得一個新的迭代器,然後開始對資料進行一筆筆的操作:
var iter = items.values();
// 印出 Fred
console.log(iter.next().value) ;
// 印出 Stacy
console.log(iter.next().value) ;

io.js 的文字範本(Template literals)支援

2015年1月28日 星期三
io.js 最大的特色,就是採用了最新的 V8 ,而且直接支援了 ECMAScript 6 的語法和特性,其中一項就是文字範本(Template Literals)的支援。這代表我們可以很容易在字串中代入其他的變數內容,就像一般的 Shell Script 一般,不必再像從前的方式,使用串接字串的方式達成。

如果想要使用這樣的文字範本(Template Literals),可以直接使用 ${} 來代入其他變數,然後以『`』字元將字串包起來,然後就可以將指定的變數內容代入到字串中:
var name = 'Fred';
var stringTemplate = `Hi, I am ${name}!`;

console.log(stringTemplate);
接著,如果你使用 io.js 來執行,就可以得到下列結果:
Hi, I am Fred!

Hackathon Taiwan 今年計畫確定!

2015年1月24日 星期六

人才培育與還原、體現並轉化人才原始價值是我們的目標,這也是目前台灣產業界應該要努力的方向,所以我們希望組織 Hackathon 活動來達成這樣人才拓撲的願景。

我們認為,黑客松的精神與文化需要被好好培養,也需要藉由持續且長久經營才會有意義,其體現的結果不只是聚在一起這樣簡單,而是動嘴、動手還要動腦的交流。因此,在大夥努力之下,Hackathon Taiwan 今年的黑客松計畫已確定,從這個月底開始,將每個月最少舉辦一次黑客松活動,年底前達成千人黑客松!(握拳)

希望藉由黑客文化中親自動手的精神,將不同領域的人才收集起來,並長期持續提供創作氛圍,使參與者相互間產生巨大的化學反應,使創新的可能性有脈絡可循。也期待能將許多具有潛力但不得其門而入的人們,引導進入到這樣熱血的世界,累積更多經驗值。

這樣的目標並不容易達成,自去年幾次的黑客松活動開始,從慘兮兮的幾個人,一直到現在的百人活動,各方面缺失逐漸補強完備,這途中經歷過許多困難,夥伴們也自掏了不少腰包,好不容易才得以存活並開始快速成長。感謝一些企業們的長期關注與投資,以及貴人大力相助,使我們陸續找到可以支撐整個計畫的資源、場地與合作機會,相信今年會是起飛的一年!

今年才剛開始,我們仍有很多事要做,也需要更多的資源與贊助,以及工作人員,畢竟,每個月都要籌劃一場數百人、至上千人齊聚一堂『微創業』的黑客松活動,實屬不易。所以,如果您願意支持並協助我們,請務必與我們聯絡!

我們也歡迎學生或各種單位與我們合作舉辦活動,相互連結,共享成果。如果你想在學校推廣黑客松,也歡迎加入我們的團隊,或與我們一同籌劃。

期許,我們從這個土地上出發,立足在這個現今世界的核心位置上,能使信念綿延拓撲到全亞洲,甚至是全世界,讓此地變成人才們的朝聖之地。:-)

更多資訊,歡迎參考 Hackathon Taiwan 的官方網站:
http://hackathon.tw/

Koa 的非同步流程設計

2015年1月23日 星期五
Koa 採用了 Generator 來控制非同步流程,所以在採用 Koa 的程式碼上,我們會看到很多 yield 關鍵字的出現。某程度來說,Generator 讓程式碼變得乾淨許多,也平坦許多,比較少出現太複雜的 Callback 高山。這對 JavaScript 來說是件不錯的事,只是,對很多開發者來說,需要點時間熟悉其概念。

總而言之,所有 yield 的關鍵字,一定只會出現在 Generator 當中,而一個 Generator 長得會是一個以『*』符號開頭的函數模樣:
function *() {
    // 工作流程
}

所以若是你仔細觀察,就會發現 Koa 的路由處理,採用的不是 callback 來處理客戶端要求,而是 Generator:
router.get('/test', function *() {
    // 處理客戶端要求的工作
});

其實不久前,舊文『如何於 KOA 實作長輪詢(LONG-POLLING)機制』已提及怎麼來掌控 Koa 的流程,雖然只是簡單提及,但已經大略展示其使用方法。簡單來說,你可以當作這個 Generator 結束後,與客戶端的連線就會結束,所以我們如果要處理非同步的工作,也必須避免和阻止這個 Generator 執行完。

使用 yield 控制 Generator 的流程

為了阻止 Generator 一下就跑完,我們會使用 yield 方法來暫停 Generator 的執行,並等待一個需要花時間的非同步工作完成。如果你對舊文的內容有印象就會知道,想要使用 yield 在 Koa 中去呼叫一個非同步機制,就需要設計一個特別的函數,其函數有一個 callback,當這個 callback 被呼叫時,代表工作完成。

如下面範例就是想要執行一個非同步函數 setTimeout(),並等待其執行完成。在這範例中,我們加上了 console.log() 印出 START 和 END 字串,便於觀察其行為:
router.get('/test', function *() {

    console.log('START');

    // 暫停 Generator 並等待工作完成
    yield function(done) {
        setTimeout(function() {
            console.log('TIMEOUT');

            // 完成,呼叫 callback 告訴 Generator 可以繼續 yield 以後的工作
            done();
        }, 1000);
    };

    console.log('END');
});

依照以上的例子,如果你用瀏覽器發送要求後,可以在 Server 端馬上看見 START 被印出來,然後經過一秒後會先出現 TIMEOUT 再出現 END。

很多人可能會覺得頭痛,因為照過去 JavaScript 的非同步概念來看,順序應該是要 START、END 然後等待一秒鐘後才是 TIMEOUT。但在 Generator 中,使用了 yield 以後並不是如此,所以你可以把它看作是一個在 JavaScript 中的特殊領域,以同步化(Synchronous)會阻塞(Block)的概念來進行邏輯設計的存在。

錯誤處理

JavaScript 一直以來,最讓人詬病的就是非同步機制的錯誤處理很麻煩,也很囉唆。在使用 Generator 之後,我們可以直接用 try-catch 的方法進行錯誤處理。如下所示:

try {
    yield function(done) {
        setTimeout(function() {
            // 拋出錯誤
            done(new Error('WRONG'));
        }, 1000);
    }
} catch(err) {
    // 處理錯誤
    console.log(err);
}

Koa 的設計上,只要將錯誤代入到 callback 的第一個參數,使第一個參數不是 null,就會拋出錯誤,讓 yield 外的 try-catch 去攔截,如此就可以很容易來處理非同步機制的錯誤。

從 yield 得到回傳結果

如果已經瞭解了 yield 的使用方式和邏輯,我們也可以等待非同步工作將一些結果回傳,就像下面的使用方式:
var result = yield function(done) { ... }

在 Koa 中,確實作法只需要代入想要回傳的資料到 callback 的第二個參數即可:

var result = yield function(done) {
    setTimeout(function() {
        // 拋出錯誤
        done(null, 'hello');
    }, 1000);
}
console.log(result);

包裝成更好用的函數

我們固然可以直接使用匿名函數,讓 Generator 去執行,但這可能不是一個好的做法,多數情況,我們還是會將功能包裝成 API 函數的形式,增加重複利用的機會,如下:
yield delay(3000);

如果你很熟悉 JavaScript 的開發,應該已經知道怎麼做,邏輯如前面所提及的範例一樣,只是額外進行一層包裝罷了:
function delay(interval) {
    return function(done) {
        // 照 interval 變數所給的數值,決定暫停時間長度
        setTimeout(done, interval);
    };
}

後記

Generator 是一個會讓傳統 JavaScript 開發者抓狂的東西,不過 Koa 對其已經做了初步的包裝,只要熟悉 callback 的使用,都不會有太大問題。但這也代表 Koa 中所用到的 Generator 機制,和原始的 Generator 使用方法會有些差別,最大差別就是沒有 callback 的設計,得自己實作。

所以,如果你是一個 Generator 的初學者,建議先不要直接學習原始 Generator 的使用方法,可以藉由 Koa 先熟悉並瞭解 Generator 的邏輯。等到都熟悉了 Generator 的概念後,再開始學習怎麼自行實作如同 Koa 的 callback。

如何於 Koa 實作長輪詢(Long-polling)機制

2015年1月22日 星期四
io.js 的到來以及即將釋出的 Node.js v0.12,意味著我們不能再忽視 ECMAScript 6 的存在,更代表著 Koa Web Framework 開始要正式進入到市場了(如果你對 Koa 有興趣,可以參考『舊文』的簡報內容,有說明完整的開發方法,也有說明 Generator 的使用方法)。Koa 大量運用到 ECMAScript 6 新的 Generator 支援,簡化了非同步的機制,更減少了 Callback 的使用場景。

平心而論,Generator 的機制對許多 JavaScript 開發者確是一個不小的門檻,與舊有的習慣格格不入,需要一點時間學習及熟悉。如果你還不熟悉其機制的細節,不如先學習一些習慣的使用,這是一個比較快能上手的方式。所以,我們可以試著來實作 Long-polling(長輪詢)機制,理解如何運用 Generator 在 Koa 中進行非同步的實作。

若開發 Web 應用涉及了即時的需求,不免碰到 Long-polling(長輪詢)的機制, Long-polling(長輪詢)簡單來說,就是讓伺服器可以即時通知客戶端有資料要進行傳送,常被用在聊天室、即時通知訊息等應用,如 Facebook 的訊息通知機制,就是採用這樣的方式。

Long-polling(長輪詢)的運行原理,就是讓客戶端向伺服器要求新的資料,但取得資料後雙方都不中止連線,等到伺服器有資料要通知客戶端時才將連線中斷,而客戶端就知道有新資料要接收,重新建立一次連線以取得新資料,然後又再次保持連線不中斷,等待下次通知。

暸解了原理,我們就可以開始實作伺服器的部分。首先,假設我們現在有一個事件發送器,每次有資料更新,就會觸發一次事件。如下範例,是每秒鐘更新一次資料:

// 建立一個事件發送器
var dispatcher = new events.EventEmitter();
var num = 0;

setInterval(function() {
    // 將 num 加一,更新資料
    num++;

    // 通知所有客戶端資料有更新
    dispatcher.emit('update');
}, 1000);

如果是 Express,若要實作 Long-polling 來即時發送最新資料到客戶端,應該不外乎這樣寫:
var events = require('events');

app.get('/poll', function(req, res) {

    // 送資料到客戶端
    res.send(num);

    // 當有資料更新
    dispatcher.once('update', function() {

        // 中斷連線
        res.end();
    });
});

如果改採用 Koa 來實作:
router.get('/poll', function *() {

    // 送資料到客戶端
    this.body = num;

    // yield 將函數內的程式暫停於此,等待之後的函數完成並呼叫 callback
    yield function(callback) {

        // 當有資料更新
        dispatcher.once('update', function() {

            // 完成工作,繼續執行 yield 之後的程式碼
            callback();
        });
    };

   // Generator 跑完,連線中斷]
});
我們可以看到,Koa 都採用 Generator 來處理客戶端要求,這樣的概念與傳統非同步的 Callback 機制有些不一樣。所以,若要在 Koa 中使用一些非同步機制,就要設計一個特殊函數讓 yield 使用,以等待工作完成,使 Generator 暫停,等 yield 的工作完成後再繼續。

很多人在看到 Generator 時,不免和過去的非同步設計搞混,一時間會懷疑 yield 是否會使 JavaScript 的事件引擎阻塞,但這其實是多慮的,因為 Generator 內的機制與一般函數不一樣,而重點是 yield 也只能在 Generator 中使用,不需要怕誤用而導致事件引擎卡死。我們應該用另一個角度來看待 Generator 的邏輯,雖然他長得很像普通的函數。

客戶端實作

雖然客戶端的實作不是本文的重點,但也在此補上,供讀者參考,以下是採用 jQuery 的實作:
function poll() {
    $.ajax({
        url: '/poll',
        type: 'get',
        timeout: 120000,
        complete: poll,
        success: function(data) {
            console.log(data);
        }
    });
}

poll();
Copyright @ 2013 Fred's blog. Designed by Templateism | MyBloggerLab
載入中…

誰在追蹤 Fred

您可以贊助 Fred 持續寫作

廣告與公益


Blog Archive