發表文章

目前顯示的是有「ECMAScript 6」標籤的文章

自幹 JavaScript 的 Tail Call Optimization

圖片
ECMAScript 6 開始,規範中出現了一項被稱為「尾呼叫優化(Tail Call Optimization, TCO)」的優化技術,這讓開發者可以在函數的執行過程中,減少 Stack Frame 的數量,進而提升效能。TCO 尤其是在遞迴這種不停呼叫自己或新函數的工作上,能得到最大的優化效益,能提升遞迴的執行效能如同迴圈一樣。 只不過很可惜的是,截至本文發稿前,大多數瀏覽器及 JavaScript 引擎尚未支援這項技術。但我們還是可以自幹並模擬一個 TCO 的行為,雖然比起語言本身、編譯器(Compiler)及虛擬機(VM)層面的實現,效果差了些,但仍然可以減少 Stack Frame 的數量避免達到 Stack Frame 的數量上限。 什麼時候會啟用尾呼叫優化機制? 如果 JavaScript 引擎有支援,通常一個函數執行到最後一行 return 時,是回傳另一個函數的執行結果,就會啟用 TCO 機制,如: const f = () => { return 999; }; const g = () => { // 執行並直接回傳 f 函數的執行結果:會啟用尾呼叫優化機制 return f(); }; g(); 但要注意的是,回傳的「必定為函數的直接回傳值」,所以下面這些寫法不會啟用 TCO 機制: // 不會啟用 TCO 機制的設計 const g = () => { return f() + 1; }; // 不會啟用 TCO 機制的設計 const g = () => { let ret = f(); return ret; }; 創造一個跑不完的函數 首先我們先創造一個肯定跑不完的遞迴,然後改善它: const func = (x) => { // 讓他跑 10000000 次 if (x === 10000000) return x; return func(x + 1); }; let ret = func(0); 理論上,如果你直接執行上述程式碼,會得到 stack size 超過上限的錯誤訊息: RangeError: Maximum call stack size exce...

Lantern 專案:快速打造屬於自己的 Isomorphic 網站服務

圖片
話說,Isomorphic 一直是 Node.js 開發者的夢想,期望同一套程式碼前後端都可以使用,大幅簡化程式碼和加速開發。此外,動態網頁的 SEO 問題也可以同時獲得解決,許多效能問題也可以得到改善。但是,要實現 Isomorphic 的架構,有很多的問題得先解決,會花大量時間在前期工作上,往往讓許多開發者頭痛。 儘管頭痛,仍然阻止不了大家往 Isomorphic 的世界前進,我也因此建立了一個專案「 Lantern 」,希望能讓更多人能以 Isomorphic 架構,快速建構出自己的網站服務,省去許多前期工作的時間。該專案是一個網站服務的樣板,實作了會員系統、權限管理、第三方登入、多國語系和送信機制等功能,在使用者介面上也做了一個還算美觀的介面。基本上,開發者只要 clone 下來,然後修改設定檔或改改介面、增加點功能,就可以快速完成一個屬於自己的全新網站服務。 最特別的是,「 Lantern 」整合了現今所有最新的技術和概念,包括了 Koa、React、FLUX、ES6/7+、Webpack 以及 Semantic UI,大量運用了 Generator、class 及 decorator 等最新 JavaScript 語言特性來簡化設計。所以,如果你想要接觸最新的技術,完全可以透過修改「 Lantern 」專案來學習和熟悉。 目前「 Lantern 」支援 Facebook 剛發佈的最新 React v0.14+ 和 react-router 1.0.0+,也避免使用像 redux 這類反 FLUX 原始設計的框架,讓原本熟悉 React 和 FLUX 架構的開發者,可以快速上手。也提供一些常見的 Extension,方便開發者寫出前後端通用的程式碼,大多數情況下,開發者不需思考程式碼運行在前端還是後端。 快速安裝使用 若想要使用「Lantern」,方式很簡單,先從 Github 取得程式碼: git clone git@github.com:cfsghost/lantern.git 安裝必要之 NPM 模組: npm install 使用 webpack 編譯專案(若要正式上線,可加上 -p 選項來編譯): webpack 運行網站服務: node app.js 最後可以使用瀏覽器開啟網址,確認是否成功: http://...

快樂玩 ES6 Generator,從 co 起手式開始

圖片
自從 Node.js 0.12 版和 io.js 之後,大量的開發者開始了各自的 ECMAScript 6 大冒險,許多人對 Generator 的使用仍跌跌撞撞,對於這種看似「同步(Synchronous)」的「異步(Asynchronous)」機制,有許多人腦袋遲遲無法轉過來。雖然在小弟的書(參閱連結: 新書報到!Node.js 模組參考手冊! )已經有清楚的說明 Generator 使用方法,但就許多讀者回函來看,對於 JavaScript 越是熟悉的人,越無法直觀理解 Generator 的思維,甚至是老是抓不准使用的時機點。 尤其是過去我們已經有 Promise、async、Q 和 bluebird 等處理非同步程式流程的模組和工具,很多人就是覺得沒有使用 Generator 的必要。不過,如果你會使用 co 模組,你會突然發現若是將過去的流程機制與 Generator 相搭配,程式開發將變得更為流暢。 若想要安裝 co 模組,可以直接以 NPM 下載: npm install co 本文接下來會說明一些 co 的基本使用,破除一些 Generator 難以使用的地方,讓開發者們更容易開始 Generator 的旅程。 讓原生 Generator 更好用 這是很多人不喜歡使用 Generator 的主因,以往為了使用 Generator,我們還要先建立一個 Generator 的函數,然後不時的去處理 Generator 所返回的資訊,一遍又一遍進入 Generator 之中。因此,無論 Generator 再好用,這些麻煩的動作也完全抵銷他的優勢,大多數人還不如回到舊的流程控制方法,以免徒增自己的麻煩。 而如果使用 co,可以直接將 Generator 函數當作「立即函數使用」,其餘的部份我們可以不需要擔心: var co = require('co'); co(function *() {     console.log('Inside'); }) 再也不用煩惱 yield! 以前光是 Promise,就已經讓很多人詬病,覺得每次使用 Promise 都要花許多時間對函數進行包裝,而 Generator 也有類似的問題,若是要使用 yield,更是一件大工程。於是,co ...

io.js 的 ES6 Collection 支援 - Set

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 的迭代器是圍繞著 Generato...

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

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!

Koa 的非同步流程設計

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 並等待工作完成     y...

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

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,若要實...

Hackathon 活動的『Koa 正在等一個人』簡報釋出!

圖片
很開心,這次十二月的『 Hackathon Taiwan 』相當多人參與,百人的報到數讓所有工作人員都感到興奮。最重要的,多虧了活動夥伴的遊戲設計,這次讓很多隻身而來的人,化解尷尬、相互認識並熱絡起來,最後順利組成隊伍,這算是種格外特別的創舉,過去很少有黑客松能做到這樣的地步。 有趣的是,這次活動找來了重量級的神秘講師 Jeremy Lu (對,就是那位最近紅極一時的 React.js 講者)開課,讓聽眾大飽耳福,絕對不枉來這一趟。有很多人也衝著 Qt 的課程而來,學習 QML 這樣先進的 UI 技術,這次的 QML 遊戲開發課程,相信讓很多人也開心地學會很多技術。 小弟在第二天的結尾,也給了篇一小時的分享『Koa 正在等一個人』,其內容在探討並帶領上手 Koa 這個下一代的網站框架、ECMAScript 6 Generator,以及 Node.js 和 io.js 的最新動態。(事實上是把最近將要出的書,擷取片段內容出來分享) 後記 對於我而言,活動內容再豐富,都比不上找到了好隊友可以一起創作。這次活動,得到了一個硬體工程師加入我們的團隊,所以可以開始進行硬體設計及控制等工作,而且大家相約了下次一起再來。下次,我們將會開始進行各種智慧家電的控制,以及 IoT 的相關應用。看來,我們只差一個設計師的加入了!如果你有興趣,快來加入我們!:-D 下次黑客松活動預計將於 2015 年 1/31、2/1(六、日)兩天,無論你是軟體開發者、硬體開發者、設計師還是學生,都歡迎來參加!而且,一樣會有神秘講師!