NodeJS用遞歸實現異步操作的鏈式調用,完成一個簡易的命令行輸入輸出REPL交互接口


REPL —— Read-Eval-Print-Loop.

00.一門好的編程語言的必要條件

REPL並不是什么高大上的東西,簡單的說就是一個從命令行程序,讀取終端輸入,處理,打印結果,如此循環。這是一門比較全面的編程語言的基礎。

剛開始接觸NodeJS,以為就是一個服務端Js,但學習了一段時間之后才感受到它的強大和魅力。如果說Java是編程游戲里一個喜歡循規蹈矩的古板選手,JavaScript就是一個天馬行空的飄逸選手。剛開始轉型異步編程非常不習慣,慢慢的懂得,異步編程,是一種思維。

 

01.依葫蘆畫不出瓢

一個命令行讀取輸入,處理的程序,Java可以寫一個while循環來不停的用Scanner來readLine,但是如果模仿Java用JS就有點麻煩了,

var rl = require('readline');
while(true) {
    rl.on('line',function(data){
        //to deal data
    });
}

這樣很顯然是不行滴,不過習慣了同步編程的猿們說不定會這樣干,JavaScript的異步意味着非阻塞式的設計,不會因為等用戶輸入阻塞下一次循環。所以要告訴JavaScript在這一次處理完之后,再進行下一次讀取(回調),那么問題來了,臭名昭著的Callback hell就有可能發生了。

 

10.如何正確畫瓢,還要看起來舒服

解決方案1:使用async,co,q, promise等等機制來同步

解決方案2:對於一個REPL程序,邏輯很簡單,如果實現一個鏈式調用的接口就好了,像這樣:

read("var1", function(data){}).read("var2",function(data){})...

 

寫原生代碼比使用開源庫更加容易調試,而且殺雞焉用牛刀,不麻煩co這樣的模塊了,q 這種then()的鏈式調用差強人意,想做什么就直接 .xx().xx()更直觀。

 

11.銀彈

用起來簡單的東西,背后一定是用更復雜或更精巧的方式掩蓋了其真實的復雜度。

repl.js

var readline = require('readline');    //非常好用的Node自帶庫

var rl = null;                                  //Singleton
var questions = [];                         //處理隊列
var cursor = 0;                               //游標

function dealQuestions(_self) {       //遞歸處理隊列中的讀取請求
    if(cursor >= questions.length) {
        cursor = 0;questions = [];
        rl.close();
        rl = null;
        return _self;
    }

    rl.question(questions[cursor].question, function (data) {
        questions[cursor].deal(data);
        ++cursor;
        dealQuestions();                      //讀取處理完畢回調
    });
}

var easyREPL = function(){
    if(rl == null) {                             //初始化模塊
        rl = readline.createInterface({
            input: process.stdin,
            output: process.stdout
        });
    }
    return this;
};

/**
 * @description : a liner api to get console input
 * @param : question to ask , function to deal answer
 * */
easyREPL.prototype.question = function(question,dealAnswer){
    easyREPL();                                 
    rl.prompt();
    var _self = this;                            //保存this指針
    questions.push({question:question,deal:dealAnswer});  //加入處理隊列
    if(questions.length == 1) {
        dealQuestions(_self);
    }
    return this;                                   //實現鏈式調用的關鍵:返回this
};

exports.REPL_Mode = easyREPL;

測試代碼:test.js

var easyREPL = require("./repl").REPL_Mode;

var test = new easyREPL();

/* comment following codes to test command mode */
test.question("Input name:" , function(data) {
    console.log("Get name:"+data);
}).question("Input password:",function(data){
    console.log("Get password:"+data);
}).question("Input Email:",function(data){
    console.log("Get email:"+data);
});

輸出:

這是一個引子,NodeJS能做的事情太多了,另外還做了一個解析輸入命令的程序,代碼比這個多,但是不夠精髓,還是不放了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM