2011-11-14 15 views
94

Pensé en crear un servidor http servidor simple con alguna extensión de consola. Encontré el fragmento para leer de los datos de la línea de comandos.Lectura de valor desde la consola, de forma interactiva

var i = rl.createInterface(process.stdin, process.stdout, null); 
    i.question('Write your name: ', function(answer) { 
    console.log('Nice to meet you> ' + answer); 
    i.close(); 
    process.stdin.destroy(); 

    }); 

bien para hacer las preguntas en repetidas ocasiones, no puedo simplemente usar el bucle while(done) { }? También, si el servidor recibe el resultado en el momento de la pregunta, arruina la línea.

+1

Supongo que por 'rl' te refieres a [readline] (https://stackoverflow.com/a/14513763/712526)? – jpaugh

Respuesta

109

no se puede hacer un ciclo "while (done)" porque eso requeriría el bloqueo de la entrada, algo que node.js no desea hacer.

su lugar estableció una devolución de llamada a ser llamado cada vez que se introduce algo:

var stdin = process.openStdin(); 

stdin.addListener("data", function(d) { 
    // note: d is an object, and when converted to a string it will 
    // end with a linefeed. so we (rather crudely) account for that 
    // with toString() and then trim() 
    console.log("you entered: [" + 
     d.toString().trim() + "]"); 
    }); 
+1

Gracias, esto funciona. ¿El oyente "final" permite llamar a algunas operaciones de cierre y decir "Adiós"? –

+0

Eliminé al oyente "final" del ejemplo; no sé dónde será realmente útil ser honesto. – rob

+0

cómo controlar datos escritos con instrucción if? o swtich caso? –

72

he utilizado otra API para este fin ..

var readline = require('readline'); 
var rl = readline.createInterface(process.stdin, process.stdout); 
rl.setPrompt('guess> '); 
rl.prompt(); 
rl.on('line', function(line) { 
    if (line === "right") rl.close(); 
    rl.prompt(); 
}).on('close',function(){ 
    process.exit(0); 
}); 

Esto permite a sugerirán el bucle hasta la respuesta es right. También ofrece una consola pequeña y agradable. Puede encontrar los detalles @http://nodejs.org/api/readline.html#readline_example_tiny_cli

+5

Esta es una gran respuesta. Lo que podría no ser obvio (pero es una gran ventaja) es que readline no es una dependencia externa: es parte de node.js. – jlh

22

La API Readline ha cambiado bastante desde los 12 '. El show de doc un ejemplo útil para capturar la entrada del usuario de una corriente estándar:

const readline = require('readline'); 

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

rl.question('What do you think of Node.js? ', (answer) => { 
    console.log('Thank you for your valuable feedback:', answer); 
    rl.close(); 
}); 

More information here.

+2

esto es solo un ejemplo básico. ¿Cómo interactúas? ¿pregunta respuesta? opciones múltiples y similares? Cómo volver a abrir rl una vez cerrado, si no se puede cómo trabajar con rl abierto para interactuar con el usuario, incluida alguna lógica –

8

@ Rob respuesta va a trabajar la mayor parte de las veces, pero podría no funcionar como se espera con entradas largas.

Eso es lo que se debe utilizar en su lugar:

const stdin = process.openStdin(); 
let content = ''; 

stdin.addListener('data', d => { 
    content += d.toString(); 
}); 

stdin.addListener('end',() => { 
    console.info(`Input: ${content}`); 
}); 

Explicación de por qué esta solución funciona:

addListener('data') funciona como un tampón, devolución de llamada se llamará cuando está lleno y/o es el final de la entrada.

¿Qué pasa con las entradas largas? Una sola devolución de llamada 'data' no será suficiente, por lo tanto, obtendrá su división de entrada en dos o más partes. Eso a menudo no es conveniente.

addListener('end') nos notificará cuando el lector esté terminado de leer nuestra entrada. Dado que hemos estado almacenando los datos anteriores, ahora podemos leerlos y procesarlos todos juntos.

8

Utilice readline-sync, esto le permite trabajar con la consola sincrónica sin resúmenes de devoluciones de llamada. Incluso trabaja con contraseñas:

var favFood = read.question('What is your favorite food? ', { 
 
    hideEchoBack: true // The typed text on screen is hidden by `*` (default). 
 
});

+0

Esto requiere una dependencia adicional, por lo que preferiría otras soluciones. –

2

Creo que esto merece un moderno async-await respuesta, suponiendo que se utiliza nodo> = 7.x.

La respuesta todavía usa ReadLine::question pero la envuelve para que while (done) {} sea posible, que es algo de lo que el OP pregunta explícitamente.

var cl = readln.createInterface(process.stdin, process.stdout); 
var question = function(q) { 
    return new Promise((res, rej) => { 
     cl.question(q, answer => { 
      res(answer); 
     }) 
    }); 
}; 

y luego un ejemplo de uso

(async function main() { 
    var answer; 
    while (answer != 'yes') { 
     answer = await question('Are you sure? '); 
    } 
    console.log('finally you are sure!'); 
})(); 

conduce a la siguiente conversación

Are you sure? no 
Are you sure? no 
Are you sure? yes 
finally you are sure! 
0

Un caso de uso común sería probablemente para que la aplicación muestre un indicador genérico y manejarlo en una declaración de cambio

Usted podría conseguir un comportamiento equivalente a un bucle while mediante el uso de una función de ayuda que llamarse a sí misma en la devolución de llamada:

const readline = require('readline'); 
const rl = readline.createInterface(process.stdin, process.stdout); 

function promptInput (prompt, handler) 
{ 
    rl.question(prompt, input => 
    { 
     if (handler(input) !== false) 
     { 
      promptInput(prompt, handler); 
     } 
     else 
     { 
      rl.close(); 
     } 
    }); 
} 

promptInput('app> ', input => 
{ 
    switch (input) 
    { 
     case 'my command': 
      // handle this command 
      break; 
     case 'exit': 
      console.log('Bye!'); 
      return false; 
    } 
}); 

Usted podría pasar una cadena vacía en lugar de 'app> ' si su aplicación ya imprime algo la pantalla fuera de este bucle.

Cuestiones relacionadas