【问题标题】:Using Q to create an async user input sequence使用 Q 创建异步用户输入序列
【发布时间】:2013-10-06 14:39:17
【问题描述】:

我在玩Qpromptly,我试图按顺序要求用户输入一些东西。例如:

What is your name? Bob
What is your age? 40
Hello Bob (40)! 

(是的!这是一个简单的“Hello world!”程序。)

这是我正在尝试的代码,直接来自 Q 的 github 项目页面:

Q.fcall(promptly.prompt, "What is your name? ")
.then(promptly.prompt, "What is your age? ")
.done(function(name, age) {            
  console.log("Hello " + name + " (" + age + ")");
});

});

但它没有按预期工作(也许我读错了?)。无论我尝试什么,似乎promptly.prompt 正在并行侦听击键,并且立即调用.done 函数,导致

/path/to/node_modules/promptly/index.js:80
         fn(null, data);
         ^
TypeError: undefined is not a function
     at /path/to/node_modules/promptly/index.js:80:9
     ...

一旦我按下 Enter。知道为什么会这样做以及我如何才能完成我想做的事情吗?

** 编辑 **

基本上,我的最终目标是创建一个像这样调用的可重用函数:

promptAll({ 
    'name': "What is your name? ", 
    'age': "What is your age? "
}).done(function(input) {
    console.log(input);  // ex: { name: "Bob", age: 40 }
});

** 更新**

这是我的工作解决方案,我必须按照WiredPraine 的建议使用nfcall

function multiPrompt(args) {
  function _next() {
    if (keys.length) {
      var key = keys.pop();
      Q.nfcall(promptly.prompt, args[key]).done(function(value) {
        result[key] = value;
        _next();
      });
    } else {
      def.resolve(result);
    }
  };
  var def = Q.defer();  
  var keys = _.keys(args).reverse();
  var result = {};

  _next();

  return def.promise;
};

注意:我使用的是下划线,但同样可以使用标准的对象迭代器来实现。)

【问题讨论】:

    标签: node.js prompt q


    【解决方案1】:

    以下是两种方法。

    首先,您需要使用 nfcall,以便 Q 使用 NodeJS 的回调约定。

    但是,由于函数不是 Promise,您需要稍微不同地处理链接和同步行为。

    在第一个示例start1 中,代码创建了一个defer 的实例并将其作为承诺返回。当prompt 函数返回时,它resolves 延迟对象实例并传递函数的value(最好是提示符)。它还应该处理“真实”代码中的错误等。

    在这两个示例中,我都添加了一个函数来获取 promise 解析的结果。它不会作为参数传递给最后一个 done 实例。传递给done 的函数将在第一个promise 解决后立即执行(在这种情况下,在prompt 返回之后)。

    var promptly = require('promptly');
    var Q = require('q');
    
    // make a simple deferred/promise out of the prompt function
    var prompter = function(text) {
        var deferred = Q.defer();
    
        promptly.prompt(text, function(err, value) {
           deferred.resolve(value);
        });
    
        return deferred.promise;
    };
    
    // this option just uses the promise option to prompt for name.
    function start1() {
        prompter("What is your name?").then(function(name) {
            prompter("Your age?").then(function(age) {
                console.log("Hello " + name + " (" + age + ")");
            });
        });
    }
    
    // this one uses the nfcall funcitonality to directly call the 
    // promptly.prompt function (and waits for a callback).
    function start2() {
        Q.nfcall(promptly.prompt, "What is your name? ")
            .then(function(name) {
                    Q.nfcall(promptly.prompt, "What is your age? ")
                        .done(function(age) {
                            console.log("Hello " + name + " (" + age + ")");
                        });
            });
    }
    
    //start1();
    

    【讨论】:

    • 来自 Q 的文档:“有两种方法可以链接 Promise。您可以在处理程序内部或外部链接 Promise。......两个示例是等价的。”我打算做第二个例子,因为我想创建一个通用的可重用函数来提示用户做事。我确信 Q 已经有一个解决方案来处理这种情况了......
    • 但是,promptly.prompt 不是一个承诺,你需要一个回调函数来接受返回值。我演示了将其包装成 Promise 并使用 nfcall 的技术。
    • 是的,第二个例子有效。这就是我从上次更新中提出解决方案的原因。 :) 效果很好!我实际上添加了更多功能以提高可控性。
    【解决方案2】:

    我觉得这里的答案可以添加到任何寻求替代方案来解决从节点获取命令行用户输入的一般问题的人。

    首先,我个人认为转向 ES6 Promises API 是有好处的。虽然 Node 中还没有原生可用,但有一个很棒的 polyfill:https://github.com/jakearchibald/es6-promise

    其次,我开始喜欢另一个用户提示模块:https://github.com/flatiron/prompt

    现在假设存在依次返回承诺的方法“addUserToDb”、“printUser”和“printError”,以下示例是可能的:

    var prompt = require('node-prompt');
    var Promise = require('es6-promise').Promise;
    
    var promptUser = function(schema) {
      return new Promise(resolve, reject) {
        prompt.get(schema, function(err, result) {
          if (err) {
            reject(err);
          } else {
            resolve(result);
          }
        });
      };
    };
    
    promptUser(["name", "password"])
      .then(addUserToDb)
      .then(printUser)
      .catch(printError)
    

    我现在使用这种方法编写了许多“脚本”,发现它非常好用并且易于维护/适应。

    【讨论】:

    • 有趣。谢谢分享!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-12
    • 2013-05-09
    • 1970-01-01
    • 2018-08-08
    • 1970-01-01
    相关资源
    最近更新 更多