zoukankan      html  css  js  c++  java
  • 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能做的事情太多了,另外还做了一个解析输入命令的程序,代码比这个多,但是不够精髓,还是不放了。

  • 相关阅读:
    codeforces 980A Links and Pearls
    zoj 3640 Help Me Escape
    sgu 495 Kids and Prizes
    poj 3071 Football
    hdu 3853 LOOPS
    hdu 4035 Maze
    hdu 4405 Aeroplane chess
    poj 2096 Collecting Bugs
    scu 4444 Travel
    zoj 3870 Team Formation
  • 原文地址:https://www.cnblogs.com/code2life/p/5052809.html
Copyright © 2011-2022 走看看