2016年10月15日 星期六

nodejs callback 初次見解

        研讀歐萊禮出版的「 Node學習手冊 」的筆記。

        從node.js官網下載到自己OS版本來安裝就行了,剛開始我用的時候,把nodejs和npm搞混在一起,以為是要一起安裝才算安裝好node環境,不過npm是javascript項目管理工具,而最近新出來的yarn也是一樣,yarn成功解決了npm為人詬病的效能問題,這個套件也是由facebook、google及其他同樣優秀的工程師共同開發,上線沒多久在github上面的star馬上超越了大家用了很久的npm。

        架設好了之後,建立一個hello.js,並打上書中的範例程式碼:

var http = require('http');

http.createServer( function (request, response) {
    response.writeHead(200, {'Content-Type': 'text/plain'});
    response.end('Hello World\n');
}).listen(8124);

console.log('Server running at http://127.0.0.1:8124/');

        terminal cd 到專案的資料夾後,執行 node hello.js

        接著我們在瀏覽器訪問:http://127.0.0.1:8124/

        結果為:


        引入模組的方式為require,這裡引用了HTTP模組並指派給一個變數,這個變數呼叫createServer來初始化網頁伺服器,這裡顯示了nodejs的基本結構:callback,以下來稍微講下我目前對callback的理解。

        上面的程式碼在createServer的function裡面又寫了一段function,而在createServer支援非同步的情況下,這段程式碼並不會受到javascript的單執行緒限制,也就是由上而下,一定要等抵達的該段程式碼塊執行完才會繼續往下一行執行下去,而在上面的程式碼中,並不用等到createServer裡的程式執行完畢,在當下就會直接先跳過並往下而繼續執行console.log,等createServer裡執行完畢之後,才會回傳。

        所以callback的概念有點像是先登記說,好,等一下如果執行OK的話再跟我說,我再去做我應該要完成做的事,你們其他人可以先做你們的事沒關係,不用管我了,套用在createServer裡面就是「 如果我這邊有回應的話,我就會去執行writeHead和end兩個動作,下面的console.log兄你可以先告訴使用者現在的訊息囉!」

        舉一個實際例子:

        阿鴻今天有很多待辦清單要做,其中一項是因為護照過期了,要去拍護照需要的大頭照,於是跑去照相館拍了張照,但拍了照之後要微調、洗照片、包裝啊,清單上面的事情像買書、剪頭髮什麼的還好多,總不可能就在店裡等照片吧,於是阿鴻便跟老闆說如果照片都好的話再跟我說,我先去辦其他事了,於是留下了個聯絡方式就去買書了。

        等到阿鴻把事情都辦得差不多的時候,剛好老闆也打過來說可以拿照片了,於是阿鴻就前往照相館取得照片,回家收工!

        留聯絡方式就是登記了個callback函數,老闆打電話給阿鴻說相片好了就是呼叫callback函數,阿鴻前往相片館就是響應callback函數。

        下面這一段書中的第二個範例程式碼會更有感覺:

var http = require('http');
var fs = require('fs');

http.createServer(function (req, res) {
    var name = require('url').parse(req.url, true).query.name;

    if (name === undefined) name = 'world';

    if (name == 'burningbird') {
        var file = 'bird.png';
        fs.stat(file, function (err, stat) {
            if (err) {
                console.error(err);
                res.writeHead(200, {'Conten-Type': 'text/plain'});
                res.end("Sorry, Burningbird isn't around right now \n");
            } else {
                var img = fs.readFileSync(file);
                res.contentType = 'image/png';
                res.contentLength = stat.size;
                res.end(img, 'binary');
            }
        });
    } else {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('Hello ' + name + '\n');
    }
}).listen(8124);

console.log('Server running at port 8124/');

        整段程式碼總共有三層,有點像inception的感覺,也就是所謂的「 事件迴圈」,在每一個callback的過程中,都可以一直執行下去,所有的function都有自己的處理時間,並不一定要等來等去,用上面的例子來說的話,阿鴻在等老闆搞定照片的同時,老闆也在等夥伴把照片修好,阿鴻跟老闆可以各自先去做其他的事情。

        值得注意的是,裡面有一個readFileSync的函數並沒有callback機制,這是因為readFileSync是同步版的,而不是非同步版,這裡暗示說,並不是所有nodejs裡的函式都是非同步版的。

        終於開始對nodejs有一絲絲了解了.....


參考資料:

https://github.com/yarnpkg/yarn
https://github.com/npm/npm
https://www.zhihu.com/question/19801131/answer/13005983
http://www.nodebeginner.org/index-zh-tw.html#event-driven-callbacks
https://www.tenlong.com.tw/items/9864761749?item_id=1023657






沒有留言:

張貼留言