重复输出到控制台 - 我在哪里插入回调?

时间:2014-05-28 09:26:53

标签: javascript node.js powershell command-line

到目前为止,这是我的代码:

var databaseUrl = "mydb";
var collections = ["users", "reports"];
var db = require("mongojs").connect(databaseUrl, collections);

newuser =       {
            email: "john@example.com",
            password: "iLoveMongo",
            sex: "male"
        };


saveuser = function(user, callback) {
    db.users.save(
        user,
        function( error, saved) {
            if( error || !saved )
                console.log( "User not saved");
            else 
                console.log( "User saved" );
                callback();
        }
    );
};

removeuser = function() {
    db.users.remove(
        {
            sex: "male"
        },
        function( error, removed)   {
            if( error || !removed )
                console.log( "User not deleted");
            else 
                console.log( "User deleted" );
        }
    );
};

finduser = function() {
    db.users.find(
        {
            sex: "male"
        },
        function(error, users) {
            if( error || !users.length )
                console.log( "No male Users found");
            else 
            {
                console.log( "male Users found" );
                users.forEach(
                    function(maleUser) {
                        console.log(maleUser);
                    }
                );
            }
        }
    )
};

updateuser = function() {
    db.users.update(
        {
            email: "john@example.com"
        },
        {
            $set: { password: "iReallyLoveMongo" }
        },
        function(err, updated) {
            if( err || !updated )
                console.log("User not updated");
            else
                console.log("User updated");
        }
    );  
}

var options = {
    1: { 
        option: "Save a User",
        execute: saveuser.bind(null, newuser, finduser)
    },
    2: { 
        option: "Remove a User",
        execute: removeuser
    },
    3: { 
        option: "Find a User",
        execute: finduser
    },
    4: { 
        option: "Update a User",
        execute: updateuser
    }
}
function read() {
    console.log("");
    console.log(" Enter your choice: ");

    stdin = process.stdin;
    stdin.setEncoding('utf8');
    stdin.on('data', choice);
};

function choice (data) {
    data = parseInt(data);

    console.log("You entered: " + data);
    console.log("You choose to do: " + options[data]["option"]);
    options[data]["execute"]();
};

read();

只有在第一个命令弹出“输入您的选择”文本时才会发生什么。您仍然可以输入数字并执行其他选项。

这是我在控制台上得到的:

PS C:\Users\Benni\Documents\nodejs> node .\mongotest\app.js

 Enter your choice:
1
You entered: 1
You choose to do: Save a User
User saved
male Users found
{ _id: 5386ba18463a008011fe6213,
  email: 'john@example.com',
  password: 'iLoveMongo',
  sex: 'male' }
3
You entered: 3
You choose to do: Find a User
male Users found
{ _id: 5386ba18463a008011fe6213,
  email: 'john@example.com',
  password: 'iLoveMongo',
  sex: 'male' }

我想要的是,在每次成功命令后(options[data]["execute"]()完成后),再次弹出“输入您的选择”。像这样:

PS C:\Users\Benni\Documents\nodejs> node .\mongotest\app.js

 Enter your choice:
1
You entered: 1
You choose to do: Save a User
User saved
male Users found
{ _id: 5386ba18463a008011fe6213,
  email: 'john@example.com',
  password: 'iLoveMongo',
  sex: 'male' }

 Enter your choice:
3
You entered: 3
You choose to do: Find a User
male Users found
{ _id: 5386ba18463a008011fe6213,
  email: 'john@example.com',
  password: 'iLoveMongo',
  sex: 'male' }

我必须再次调用read()?如果我将其放在choice的末尾,则会在options[data]["execute"]();完成之前弹出“输入您的选择”。如果我把它放在read的末尾,我将得到一个无限循环/超出最大调用堆栈大小。

或者我可以向options[data]["execute"]();添加回调吗?像

这样的东西
function( null, read){
  options[data]["execute"]();
};

3 个答案:

答案 0 :(得分:1)

您遇到的基本问题是,在数据库方法完成后,您的消息显示应该会发生。您通过回调报告完成,但问题是并非所有方法都提供回调以确定何时完成。现在即使你没有,你在调用方法时没有注册回调。所以你应该在你的所有函数中定义一个回调参数,然后在你的阅读中注册一个回调:

newuser =       {
            email: "john@example.com",
            password: "iLoveMongo",
            sex: "male"
        };


saveuser = function(user, callback) {
    db.users.save(
        user,
        function( error, saved) {
            if( error || !saved )
                callback( "User not saved");
            else                 
                callback(saved);
        }
    );
};

removeuser = function(callback) {
    db.users.remove(
        {
            sex: "male"
        },
        function( error, removed)   {
            if( error || !removed )
                callback( "User not deleted");
            else 
                console.log( "User deleted" );
                callback();
        }
    );
};

finduser = function(callback) {
    db.users.find(
        {
            sex: "male"
        },
        function(error, users) {
            if( error || !users.length )
                callback( "No male Users found");
            else 
            {
                console.log( "male Users found" );
                callback(null, users);
            }
        }
    )
};

updateuser = function(callback) {
    db.users.update(
        {
            email: "john@example.com"
        },
        {
            $set: { password: "iReallyLoveMongo" }
        },
        function(err, updated) {
            if( err || !updated )
                callback("User not updated");
            else
                console.log("User updated");
                callback(null, updated);
        }
    );  
}

var options = {
    1: { 
        option: "Save a User",
        execute: saveuser.bind(null, newuser)
    },
    2: { 
        option: "Remove a User",
        execute: removeuser
    },
    3: { 
        option: "Find a User",
        execute: finduser
    },
    4: { 
        option: "Update a User",
        execute: updateuser
    }
}
function read() {
    console.log("");
    console.log(" Enter your choice: ");

    stdin = process.stdin;
    stdin.setEncoding('utf8');
    stdin.on('data', choice);
};

function choice (data) {
    data = parseInt(data);

    console.log("You entered: " + data);
    console.log("You choose to do: " + options[data]["option"]);
    options[data]["execute"](function(err, res){
        if(err){
            console.log(err);                
        }
        if(res){
            if(Array.isArray(res)){
                res.forEach(function(item){
                    console.log(item);
                })
            } else {
                console.log(res);
            }
        }
        console.log(" Enter your choice: ");
    });
};

read();

使用承诺

此案例的另一种解决方案是使用promises。这样,您对数据库的调用可以返回一个承诺,您可以稍后使用该承诺等待适当的响应。

我在这个答案中使用了Q Promises,但你可以使用你想要的任何其他库。您可以查看如何为项目获取Q here

我们可以从确保您的数据库服务返回一些内容开始,在这种情况下是一个承诺。对于这个问题,我将使用Q.ninvoke将基于回调的函数转换为promise。

var Q = require('q');
saveUser = function(user) {
    return Q.ninvoke(db.users,"save", user)
        .then(function(user){
            console.log("User saved: %j", user);
        })
        .catch(function(error){
            console.log("Error while saving: %s", error);
        });
};

removeUser = function() {
    return Q.ninvoke(db.users,"remove", {sex: "male"})
        .then(function(result){
            console.log("User removed: %j", result);
        })
        .catch(function(error){
            console.log("Error while removing: %s", error);
        });
};

findUser = function() {
    return Q.ninvoke(db.users,"find", {sex: "male"})
        .then(function(user){
            console.log("User found: %j", user);
        })
        .catch(function(error){
            console.log("Error while finding: %s", error);
        });
};

updateUser = function() {
    return Q.ninvoke(db.users,"update", 
        {
            email: "john@example.com"
        },
        {
            $set: { password: "iReallyLoveMongo" }
        })
        .then(function(user){
            console.log("User updated: %j", user);
        })
        .catch(function(error){
            console.log("Error while updating: %s", error);
        });
};

您可以注意到我的所有服务方法现在都返回了一些东西,而在原始设计中它们是无效的。

最后,您可以将阅读程序更改为:

function read() {
    console.log("");
    console.log(" Enter your choice: ");

    stdin = process.stdin;
    stdin.setEncoding('utf8');
    stdin.on('data', choice);
};

function choice (data) {
    data = parseInt(data);

    console.log("You entered: " + data);
    console.log("You choose to do: " + options[data]["option"]);
    options[data]["execute"]().then(function(){
        console.log("Enter your choice: ")
    });
};

read();

请注意,在这种情况下,options [data] [“execute”]的执行如何使用promise。承诺执行的成功保证您不会显示“在完成其他任务之前输入您的选择”。

瞧,输出是:

Enter your choice: 
1
You entered: 1
You choose to do: Save a User
User saved: [{"email":"john@example.com","password":"iLoveMongo","sex":"male","_id":"5388f57035a2eda13b7e4ea7"},{"n":0}]
Enter your choice: 
2
You entered: 2
You choose to do: Remove a User
User removed: {"n":2}

正是你想要的。

答案 1 :(得分:0)

function choice (data) {
    data = parseInt(data);

    console.log("You entered: " + data);
    console.log("You choose to do: " + options[data]["option"]);
    options[data]["execute"]();

     process.nextTick(function(){
       console.log("");
       console.log(" Enter your choice: ");
     });    
};

答案 2 :(得分:0)

您可以考虑使用内置的readline模块来帮助您完成以下任务:

var readline = require('readline');

var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

function choiceHandler(choice) {
  choice = parseInt(choice, 10);
  if (isNaN(choice))
    console.log('Bad choice, try again');
  else {
    console.log('You entered: ' + choice);
    console.log('You chose to do: ' + options[choice]['option']);
  }
  rl.prompt();
}

console.log('');
rl.setPrompt(' Enter your choice: ');
rl.on('line', choiceHandler);
rl.prompt();