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

How to convert an event listener to a promise using Q

大家好,我是 nodejs 的新手,我正在尝试学习 promises。我正在尝试实现一种菜单,该菜单将根据用户输入执行某些功能。这是我正在使用的代码:

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() 与事件侦听器之间。我希望 promise 链仅在事件侦听器被激活后才继续,但老实说我不确定该怎么做。

这是我的结果:

(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 return 是一个你想要等待的承诺,没有 return 那里的过程在 [= 之前​​继续进行14=] 已解决
  • 在几个函数中你创建了一个 deferred 但没有使用它 - 删除了那些
  • 其他地方你创建一个你解决的延迟 return,只是 return 一个 q.resolve()

下面的代码根本没有使用 q promises,我已经改为原生 Promise 来测试我的答案 - 但转换回 [=16= 应该很简单]

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();