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

  • 相关阅读:
    Robot Framework--06 用户关键字User Keyword
    Robot Framework--05 案例设计之流程与数据分离
    Robot Framework--04 工作区
    Robot Framework--03 案例及资源区
    Robot Framework--02 菜单栏&工具栏
    Robot Framework--01 创建简单工程示例
    uoj#35 后缀排序(后缀数组模版)
    【学习笔记】动态树Link-Cut-Tree
    【随意学学】三分法
    【学习笔记】dsu on tree
  • 原文地址:https://www.cnblogs.com/code2life/p/5052809.html
Copyright © 2020-2023  润新知