嗨,第一个问题!无论如何,我正在写一个小实验来帮助更好地掌握流和结合流和承诺的更复杂的组合。
但是,我遇到了一个我目前无法解决的问题。如果您运行我的以下脚本然后输入输入,然后按 ctrl-d 结束输入:节点将尝试根据需要从标准输入读取,但由于标准输入已结束而立即关闭。那么有没有更好的方法来写这个?或者有没有办法重置标准输入流以再次输入?或者有没有更好的方法来停止要求输入以等待结束事件来解决我的承诺?
另请注意:在节点 5.1.0 上运行,使用 ES2015(通过 Babel 6)
import { Transform, Writable } from 'stream';
import util from 'util';
/**
* Generic Transform
* A test class to expiriment with creating a series of transforms
*
* @class
* @extends {stream.Transform}
*/
class GenericTransform extends Transform {
constructor (transformCallback, options={}) {
super(Object.assign({}, options, { objectMode: true }));
this._transformCallback = transformCallback;
}
/**
* Transform
* Stream method to transform read data, transform it, then move it to
* the next stream.
*
* @method
* @param {buffer} chunk - Buffer read from the input stream
* @param {string} enc - Encoding of the input stream chunk buffer
* @param {function} done - Callback to fire when transform is complete
*/
_transform (chunk, enc, done) {
try {
this.push(this._transformCallback(chunk, this));
done();
}
catch (e) {
this.emit('error', e);
done(e);
}
}
}
/**
* Stdout Writer
* Handles writing to stdout including linebreaks. I believe this is
* required as writing to the stdout stream will not emit end\finish events.
*
* @class
* @extends {stream.Writable}
*/
class StdoutWriter extends Writable {
constructor (options) {
super(options);
}
/**
* Write
* Stream method to write to process.stdout
*
* @method
* @param {buffer} chunk - Text that gets written to the console
* @param {string} enc - Encoding of the buffer
* @param {callback} done - Callback to call when finished
*/
_write (chunk, enc, done) {
process.stdout.write(String(chunk) + '\n');
done();
}
}
/**
* To
* A shorthand function to create a generic transform method
*
* @method
* @public
* @param {function} transformer - transformer(data) returns new data
* @returns {GenericTransform} A generic transform stream
*/
function to (transformer) {
return new GenericTransform(transformer);
}
/**
* Prompt
* Requests input from the user then transforms it. Ideally it would ask for
* input. When it receives a line it would stop reading, transform the data
* then when the stream is finished ask the user for more input.
*
* @returns {Promise} A promise when the input has been read, transformed,
* and displayed to the console via process.stdout.write
*/
function prompt () {
process.stdout.write('Enter some input: ');
return new Promise((resolve, reject) => {
/** Start with process.stdin input stream */
process.stdin
/**
* Converts the raw string input into a simple object with
* a contents property and a date property
*
* @example
* > Test
* > (ctrl-d)
* {contents: "Test", date: 43993991013 }
*/
.pipe(to((chunk) => {
return {
contents: String(chunk).trim(),
date: Date.now()
};
}))
/**
* Takes the object created from the previous step and formats it as
* a string using the inspect util. I suppose JSON.stringify would
* also have worked.
*/
.pipe(to((obj) => {
return util.inspect(obj);
}))
/**
* Pipe to a writable stream that writes to stdout. This is necessary
* because the docs say that stdout never emit finish or end events.
*/
.pipe(new StdoutWriter())
/**
* Handle errors and finish events by either resolving or rejecting
* the parent promise object.
*/
.on('finish', resolve)
.on('error', reject);
});
}
/** Set the encoding so it all comes in as strings */
process.stdin.setEncoding('utf8');
/**
* This is the main driver logic for connecting the above pieces. It will
* input the first question then keeps asking for more input. To stop
* entering data press ctrl-d to send an EOF to process.stdin. This
* at least causes the finish event to fire at the end but on the next
* usage of prompt, everything is done.
*/
prompt()
.then(prompt);