如何使用Q将事件侦听器转换为承诺

大家好,我是新来的nodejs,我试图学习承诺。 我试图实现一种菜单,将根据用户input执行某些function。 以下是我正在使用的代码:

var q = require('q'); var readline = require('readline-sync'); function createNewPreset(){ var deferred = q.defer(); var preset = { "name" : undefined, "unit" : undefined, "interval" : undefined, "files" : [], } deferred.resolve(preset); return deferred.promise; } function addPreset(){ console.log("adding"); var deferred = q.defer(); createNewPreset() .then(function(){ console.log("Gettind input in addPreset"); }) .then(getUserInput) .then(function(data){ console.log("Adding data" + data); }); } function getUserInput(){ var deferred = q.defer(); var stdin = process.stdin; stdin.resume(); stdin.once('data', function(data){ data = data.toString().trim() if(data.length > 20){ var err = new Error("The entered preset name is too long"); deferred.reject(err); } else{ deferred.resolve(data); } }); return deferred.promise; } function processChoice(input){ var deferred = q.defer(); var error = undefined; var func; switch(input){ case "a": func = addPreset; break; case "q": func = function(){ process.exit(); } break; default: error = new Error("Invalid menu option entered."); deferred.reject(error); break; } deferred.resolve(func); return deferred.promise; } function prompt(){ var stdout = process.stdout; //indicates that prompt is being executed stdout.write("(tic): "); console.log("Waiting for input"); getUserInput() .then(processChoice) .then(function(func){ func(); }) .catch(function(err) {console.log(err)}) .then(prompt); } prompt(); 

我相信问题在于getUserInput()addPreset() ,并带有事件监听器。 我希望承诺链只在事件监听器被激活后才能继续,但我不确定如何做到这一点。

这是我的结果:

 (tic): Waiting for input a adding Gettind input in addPreset (tic): Waiting for input A Adding dataA [Error: Invalid menu option entered.] (tic): Waiting for input 

我想让链等待事件监听器在继续之前执行。 有什么办法可以做到这一点?

你的代码有一些错误

没有特别的顺序

  • .then(function(func){ func(); })应该是.then(function(func){ return func(); }) – 因为func返回一个你希望等待的promise,在addPreset解决之前addPreset继续
  • 在几个函数中,您创build了一个延迟而不使用它 – 删除了这些函数
  • 其他地方你创build一个延迟,你解决并返回,只是返回一个q.resolve()

下面的代码根本不使用q promise,我已经更改为原生Promise来testing我的答案 – 但它应该是微不足道的转换回q

 function createNewPreset(){ return Promise.resolve({ "name" : undefined, "unit" : undefined, "interval" : undefined, "files" : [], }); } function addPreset(){ console.log("adding"); return createNewPreset() .then(function(){ console.log("Gettind input in addPreset"); }) .then(getUserInput) .then(function(data){ console.log("Adding data " + data); }); } function getUserInput(){ return new Promise(function(resolve, reject) { var stdin = process.stdin; stdin.resume(); stdin.once('data', function(data){ data = data.toString().trim() if(data.length > 20){ var err = new Error("The entered preset name is too long"); reject(err); } else{ resolve(data); } }); }); } function processChoice(input){ return new Promise(function(resolve, reject) { var error = undefined; var func; switch(input){ case "a": func = addPreset; break; case "q": func = function(){ process.exit(); } break; default: error = new Error("Invalid menu option entered."); reject(error); break; } resolve(func); }); } function prompt(){ var stdout = process.stdout; //indicates that prompt is being executed stdout.write("(tic): "); console.log("PROMPT waiting for input"); getUserInput() .then(processChoice) .then(function(func){ return func(); }) .catch(function(err) {console.log(err)}) .then(prompt); } prompt();