使用 Q 创建异步用户输入序列



我正在玩弄Q并迅速,我试图按顺序要求用户输入一些东西。例如:

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
     ...

一旦我按回车键。知道为什么要这样做以及我如何完成我想做的事情吗?

**编辑**

基本上,我的最终目标是创建一个可重用的函数,如下所示:

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;
};

注意:我使用的是下划线,但使用标准对象迭代器也可以实现相同的效果。

以下是两种方法。

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

但是,由于函数不是承诺,因此您需要以略微不同的方式处理链接和同步行为。

在第一个示例中,start1 ,代码创建 defer 的实例并将其作为 promise 返回。当 prompt 函数返回时,它会resolve延迟的对象实例并传递函数的value(理想情况下是提示)。它还应该处理"真实"代码中的错误等。

在这两个示例中,我都添加了一个函数来获取承诺解析的结果。它不会作为参数传递给最后一个done实例。传递给 done 的函数将在解析第一个承诺后立即执行(在这种情况下,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();

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

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

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

现在假设存在方法'addUserToDb','printUser'和'printError',它们反过来返回promise,以下示例是可能的:

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)

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

最新更新