發表文章

Node.js 小密技:以 Readline 核心模組一行行讀取檔案內容

圖片
最近參與了一些關於資料處理的專案,處理了很多各式各樣的原始資料(Raw Data)或各種不同格式的資料,於是使用到了 Node.js 上的一些小技巧。像是一行行讀取檔案內容這件事,就隱藏了一些技巧。 對很多人來說,處理的檔案內容都不大,如果用 Node.js 來一行行讀取檔案內容,不外乎就是將整個檔案讀出後再進行切割,做法大致上如下: var fs = require('fs'); fs.readFile('example.txt', function(err, data) { // 以換行字元作為切割點,將內容切成一個大陣列 var lines = data.split('\n'); lines.forEach(function(line) { // 一行行處理 }); }); 但有些時候,由於檔案並不小,若又牽涉到運算,不可能整個檔案都讀出到記憶體上才進行切割,這時就得用到 Stream(資料流)機制,將檔案一段段讀出來進行處理。然後,為了進行一行行的切割,我們會自己做這樣的機制,先將一段段讀取出來的檔案內容放到緩衝區(Buffer),然後找到換行字元進行切斷取出,然後再繼續讀取檔案,重複這樣的過程直到檔案結尾。 的確,實做這樣的機制有點麻煩,所以其實能利用 Node.js 現成內建的核心模組 Readline 來做到切割資料流中一行字串的工作。因為常見的 Readline 用法都是拿來做終端機字元模式下的命令列操作,所以許多人沒有想到可以這樣使用 Readline。作法其實很簡單,就把 Readline 的 input 從標準輸入(Standard Input)換成我們的檔案讀取資料流就可以。 完整做法如下: var fs = require('fs'); var readline = require('readline'); // 建立檔案讀取資料流 var inputStream = fs.createReadStream('example.txt'); // 將讀取資料流導入 Readline 進行處理 var lineReader = readline.createInterfac...

產品開發玩技術很過癮!實作 QML 動畫背景!

圖片
由於最近在開發自己的產品,又開始重操舊業,開發起 Linux 系統的相關應用和嵌入式技術。為了這個產品,精心開發了一個使用者介面,除了動手把驅動程式搞定、圖形化介面搞定,也調教效能、改善系統架構。 開發自己的產品很過癮,愛怎麼搞就怎麼搞!於是,看到死板的背景覺得很不舒服,就在思考是否可以跑個動畫背景呢? 因為使用的是 QML 技術來開發 UI,最直接的想法,就是用 QtMultimedia 的 MediaPlayer 無限循環播放一個影片,當作動畫背景: MediaPlayer { id: bg; source: 'bg.mov'; loops: MediaPlayer.Infinite; autoPlay: true; } VideoOutput { anchors.fill: parent; source: bg; } 當然,我們選擇的背景影片,是一個開頭跟結尾一樣的影片,如果正確循環播放,會無縫接軌的變成一個順暢的動畫背景。 然而,結果不如預期,碰到了一個問題,那就是每當背景影片播放到最後時,會畫面變成全黑,然後才再一次重新開始播放,沒辦法「無縫接軌」。仔細暸解以後,發現 MediaPlayer 元件是 QMediaPlayer 的 QML Type 實作,所有秘密都藏在 QMediaPlayer 之中。因為 QMediaPlayer 預設所有的通知事件,都是固定以 1000ms(1秒)的頻率來觸發,這代表,當 QML 元件發現影片播完時,通常已經是播完以後的事了,所以畫面一定會因為影片結束而變黑,然後 QML 元件才發現影片結束,重新進行播放。 知道緣由後,我們可以從事件更新頻率下手,讓 QML 元件發現影片播完的時間更接近實際影片結束的時間,但這必須動用到 C/C++ 的實作,因為 QMediaPlayer 的事件更新頻率無法以純 QML 的方法修改。 C/C++ 完整應用程式的實作如下,我們把更新頻率調高為每 100ms 一次: #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQuickWindow> #include ...

JavaScript 好用的 async 異步函數!

圖片
先聲明,async 異步函數是 ECMAScript 第七版(ES7)才被支援的語法和特性,目前 ES7 還沒有被大多數的 JavaScript Engine 所實作,如果你要使用,需要用到 babel 這類工具,先把此程式編譯轉換,讓其可在舊版本 JavaScript Engine 上執行。 如果你覺得以 co 模組來操作 Generator 很好用,你可以想像 async 異步函數就是原生的 co,幾乎是同樣的使用方式,同樣的使用概念,只不過不再需要使用 generator 和 yield 這類語法。如果你是個過不了在函數上有個醜陋「*」符號這一關的人,async 異步函數的使用方式應該會讓你感覺到舒服許多。 什麼是 async 異步函數(async functions)? 異步函數使用方式其實和一般的函數一樣,只不過在這函數之內的程式,可以用 await 的語法去執行並等待異步工作(如:Promise)而不需要使用到骯髒的 callback function。宣告並使用一個 async 異步函數,就是在定義函數時加上「async」,然後直接執行這個函數即可,簡單的範例如下: async function myAsyncFunc() { console.log('Hello async functions!'); } myAsyncFunc(); 搭配 Promise 的使用 Promise 通常被大量用來管理非同步的工作,並讓開發者容易管理錯誤拋出等機制,一個典型的 Promise 使用如下: var task = new Promise(function(resolve, reject) { // 執行一個非同步的工作,完成後呼叫帶入的 callback doAsyncTask(function(err) { // 有問題呼叫 reject,並帶入錯誤值 if (err) return reject(err); // 成功呼叫 resolve 並帶入回傳值 resolve('VALUE'); }); }); // 使用 then 去執行並等待工作完成,成功會呼叫 callba...

下一代的框架:Koa 1.0 起手式

圖片
身為 Node.js 使用者的你,還在使用 Express 嗎?快來使用下一代的 Web Framework 吧!Koa 是由 Express 的開發者們出來所開發的新網站框架,嘗試採用了最新的 ECMAScript 6 語法,讓開發者可以用更簡約的方式,開發網站應用程式,讓程式碼更好維護之外,也能受益於最新的語言特性。 穩定版與不穩定版 現在的 Koa 分為 1.0 和 2.0 兩個版本,1.0 使用 ES6 的 Generator 特性,也是目前的 stable 版本,而 2.0 採用 ES7+ 的 async/await,據 Koa 官方說法,2.0 穩定度可以用於實際產品,只是在 ECMAScript 7 規格正式敲定,且 JavaScript V8 Engine 推出原生的實作之前,將無限期處於 unstable 的狀態。也就是說,若你想要在你自己的專案上使用 2.0,你必須使用 babel 這一類的編譯器,因為裡面用到了 ES7 的語法。 本篇文章的重點將放在 Koa 1.0 之上,畢竟在 ECMAScript 7 還處於草案階段的現在,很難說未來會不會有什麼改變。 安裝 Koa 由於 Koa 需要用到 ECMAScript 6 的語言特性,請先檢查你的 Node.js 版本,最少為 0.12 以上,如果你已經使用了 Node.js 4.0 或更高版本,請不用擔心這個問題。 然後透過 NPM 即可安裝模組: npm install koa 開發第一個應用程式 開發 Koa 應用程式非常容易,下面是程式碼範例: var koa = require('koa'); var app = koa(); app.use(function *() { this.body = 'Hello World'; }); app.listen(3001); 跑起來後,用瀏覽器連入 3001 埠即可看到「Hello World」的字樣,因為 this.body 的內容,將會被輸出到前端瀏覽器上。 使用 Generator 打造的 Middleware koa.use() 將用來載入 Middleware,所有連線工作都會經過 Middleware 處理。所以前一個例子裡,我們...

MakerBoard: 自幹 MT7688 模擬器!簡報釋出!

圖片
使用 MTK LinkIt Smart 7688 這類開發板時,總是很痛苦,由於儲存空間不大,記憶體也不大,常常在開發的過程中飽受折磨。於是我們開始思考如何可以在自己的電腦上,模擬一個 MT7688 的環境,在有充沛資源的機器上進行開發。就這樣,前陣子開發了一個小小的 Open Source 工具專案「MakerBoard」,並在 MakerCup 的共筆網站發表「 沒有板子也可以玩的 7688 模擬器! 」。 雖然這樣一個小小的模擬器運用了 VM 和 Container 相關技術。但其實主要概念並不難,這次 5/10 在台大的開放原始碼課程中,就簡單從 MakerBoard 這專案出發,然後說明了一下怎麼樣自己打造一個簡單的 Container,並利用 QEMU 來進行 Binary Translation 的工作。 簡報釋出,請自行服用:

從 Maker 出發並反思:於是我們成立了 MakerCup!

圖片
Maker 一詞近年來翻紅,有人稱「自造者」,有人稱「創客」,以代工起家的國內產業,覺得 Maker 風潮是一個維持舊有工業地位的方法和機會,更將其引伸成軟硬整合、創業模式,無一不紛紛出來插手,想佔一塊地,分一杯羹。有些媒體將 Maker 塑造成有專業技術能力的人們,彷彿與一般人有很大的鴻溝。種種因素,自然越來越多人不了解 Maker 是什麼了。 但我們認為真正的 Maker 並不是擁有厲害能力的人,而是願意動手落實的人。 為什麼我們要成立 MakerCup? 我們想聚集純粹想動手、交流的朋友,並讓更多人參與並體驗 Maker 的世界。 事實上,Maker 的定義很簡單,凡是能打造、做東西的人,都能稱為 Maker。做菜的廚師,是個 Maker;編織衣服的人,是個 Maker;畫家,也是個 Maker。當然,寫軟體、做電子電路的人,以及各種設計師,通通都算是 Maker。無論在什麼領域,Maker 精神強調的是動手去實現、完成,去參與過程、瞭解過程,進而讓自己更有能力去打造出更多創意十足的東西。更重要的是,在這種不設限的旅程,能讓我們都具備著跨領域思考的能力。 既然過程才是最重要的,我們便開始思考怎麼樣讓更多人交流,交流技術、能力,共同發展和探討更多的知識。我們不應該只是追求一時且短暫的成果,滿足政府或代工產業想要立即成果的 KPI,更或是不應該鑽牛角尖盲目追求頂尖技能,而是讓更多人參與、動手,普遍瞭解更多不同的事物和技能。 於是, MakerCup 這個社群出現了,每週四都會舉辦一場分享交流活動或是小聚會,讓 Maker 平日下班或閒暇時,可以來走走坐坐,輕鬆喝點小飲料,或是現場做點東西: https://www.facebook.com/groups/MakerCup/ 我們希望,這個社群將如一碗太古時代的生命濃湯一般,熬煮出真正的 Maker 生命。 延續黑客松台灣的精神 還記得這一年,我們籌辦了整個年度的「 黑客松台灣(Hackathon Taiwan) 」,每個月都有 300 至 500 人的大型創作活動,讓不敢踏出來的年輕學子、上班感到無聊的人、及很少離開自己專業領域的朋友,走出來到活動上以「能力會友」。這一年的過程,讓大家的成果,從簡陋成長到真正的創意或產品,從簡單的技術到複雜的應用,從小設計到跨領域的整合。 ...

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://...

Git 大哉問:如何為 Fork 出來的專案,同步上游的更新?

圖片
搭配使用 Git 進行開發工作,時常會碰到一個狀況,就是我們 fork 一個專案出來修改,但在我們在修改的同時上游有了更新,這時我們會想要把上游的更新同步下來。這是一個常見的問題,許多人不時會提出來詢問,事實上如果你去 Google ,多半能找到這樣一篇名為「 Syncing a fork 」的 Github 文件。雖然這篇文章已經把程序詳細列出來了,但還是有人看不太懂,原因是要搭配「 Configuring a remote for a fork 」這一篇文件一起看才知道來龍去脈。 簡單來說,我們要先把「上游(upstream)」的 repository 加入我們眼前正在修改的專案,然後把上游更新拉回來,最後再與我們現有程式碼合併。 首先,加入上游的 repository 並命名為「upstream」: git remote add upstream https://github.com/YOUR_USERNAME/YOUR_FORK.git 未來想要更新前,可以使用 fetch 去拉上游的更新回來: git fetch upstream 最後再把 upstream 的內容,與現有的正在修改的進行「合併」: git merge upstream/master

Fluky - 打造 Isomorphic App 的副產品:一個基於事件驅動的 Flux 框架

圖片
要講到 Fluky 這一個 Flux 框架,這要從我的一個新計畫說起。因為最近又重新興起了一波 Isomorphic App 的熱潮,許多人開始打造了自己的 Isomorphic 網站,自己也做了一個。而什麼是 Isomorphic 呢?簡單來說,就是寫一次程式,然後前後端都可以使用的機制,也是一個網站服務工程師的夢想。還記得過去自己曾實作了 frex.js 試圖達成 API 層面的 Isomorphic,現在 React 這樣的前端框架,更提供了一個打造前後端 Rendering 的 Isomorphic,使得原本在前端動態產生的畫面,可以在後端產生,更一舉解決了 SEO 的問題。 話說,搭上了這波熱潮,最近開始土炮自己的 Isomorphic App,Github 上開啟了一個「 Lantern 燈籠 」專案,希望做一個標準的專案架構,讓自己以後開發新專案時,可以不需要重新再來一遍。痛苦的是,與很多人一樣,踩到了很多地雷,在專案架構設計上,也一直有很多許要調整的地方,這也難怪,畢竟這是一個興新的開發概念。 於是從零到有的過程中,也有許多副產品,其中包括了一個新的 Flux 框架「Fluky」。很多人問我為什麼不採用當今紅遍半天邊的「redux」,原因其實很簡單,我不想脫離傳統 Flux 模式和 React 開發的概念太遠,然後同時想要用試著更精簡的方式描述這些流程。另外一點是,受到過去 X11 這世界最先進的網路圖形化視窗系統的設計所啟發,打算試著全面使用「事件」來管理資料流和程式上任何的溝通。 如果你有興趣,可以直接以 NPM 來安裝這個 Flux 框架: npm install fluky Fluky 的設計 基本上, Fluky 本身的概念很簡單,幾乎所有的行為都是透過 Fluky.dispatch() 這個 API 來進行,包括呼叫 Action、Store,然後所有的行為都可以使用 Fluky.on() 所監聽。也就是說,只需要這兩個 API,幾乎就已經足夠。對於 View 的工作而言,永遠就是呼叫 Fluky.dispatch('action.*') 和監聽 Fluky.on('store.*') 。 這樣設計有什麼好處呢?因為所有的訊息和命令傳遞,都有統一的事件機制和命名規則,理論上來說,事件...

Node.js 的單執行緒(Single Thread)設計,到底有什麼優點?

圖片
這是個總有人一問再問的問題,到底 Node.js 這樣單執行緒(Single Thread)的設計,到底有什麼優點?為什麼總是有人說,它比傳統多執行緒的設計來得有效率?以往,一旦開始討論這個問題,總是會有人開始提到 Context Switch、Asynchronous 等機制,越講越玄也越講越複雜化。 其實我們可以用簡單的餐廳比喻,就能理解 Single Thread 加上事件驅動(Event-driven)的機制,如何與傳統設計不一樣。 場景想像 試想一個場景:一間餐廳有 100 個座位,然後來了100個客人。 處理方法 身為老闆的你,你會選擇哪種方式服務這些客人: 請100個服務生一對一服務這些客人。 請 25 個服務生,看當下狀況服務這些客人。 一般來說,傳統的多 Multi-thread 的設計就類似方法 1,而 Single-thread 且 Event-driven 的設計就是方法 2。 通常大多數情況我們會選擇方法 2,因為客人通常都是處於等待(看菜單、等上菜、吃自己)的情況,並不需要服務生貼身服務。所以即便請 100 個服務生,這些服務生大多數時間也只是等在那也佔地方,而服務生眾多也導致服務生之間的溝通和互動其實不易,更不容易交換資源,回報和協同工作難以進行。反而安排一個小型的外場班,讓裡面的人合作見機行事,會比派出 100 個各自獨立的人來得好。 併發數高的原因 併發數(concurrent request)指的是單位時間內可以處理的要求量,一般用來評估一個網路應用程式的效能。而通常在網路服務裡,併發數也相當於單一時間內能服務的連線數量。 所以,以前面餐廳外場班的模型來說,如果你有 100 個服務生,就可以服務 400 個客人。換句話說,同樣的資源,能處理的併發數(concurrent requests)也就比較高。 後記 不過如果你開的是酒店或按摩店,那可能就要請一百位服務生了。:-)

Geek?技客?是什麼?我不宅,我用動手代替說話!

圖片
因為我對外都自稱一個 Geek,所以時常有人問我,Geek 是什麼?一直以來,「技客(Geek)」個名詞讓許多人感到陌生,甚至對這詞彙一知半解的人,都以為 Geek 與普通宅宅無異,更甚至是覺得這只是另一種宅宅的說法。的確,Geek 某些地方與普通宅宅很相近,指的是醉心於特定專業或領域的人,但這些人擁有絕佳才能,只是為了鑽研知識或研究新事物可以幾乎荒廢其他事,廢寢忘食對他們來說只是小意思,甚至可以犧牲人際關係等一般正常社會交際行為。由此可以看出 Geek 對於自有興趣的事物,將會多努力去鑽研。 不可否認,「技客(Geek)」這個詞在早期帶有貶意,但在現今社會中,人們交流的手段和方法已經透過科技有很大的改變,Geek 可以透過網路或各種新方法,找到能分享交流的同好朋友。透過網路串連,他們不再只是群體中被傳統主流排除在外的人,反而搖身一變,變成強力促使世界進步的主要群體。如今,大家眼中的 Geek ,代表著才能與努力,更代表能「動手完成任務」的傑出人們。開玩笑的說,專心致志(宅宅)加上真正動手實做的能力,就是「技客(Geek)」。 想要成為一個 Geek 嗎?只要你符合這樣的條件,無論你原本是個技術 Hacker、Maker 還是個設計師,更甚至是任何領域的人,都可以稱自己是一個 Geek,甚至可以以此為榮!也許,你也有自己沒發現,但是能堪稱 Geek 的一面也說不定! 後記 為了讓更多 Geek 能聚集在一起交流,共同迸出創新的火花,我們 Hackathon Taiwan 開始了一個新計畫 GeekBar I/O,將嘗試透過各種活動和方式,讓 Geek 們共同發光發熱!歡迎大家共襄盛舉!

快樂玩 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 ...