I'm trying to get my head around generators and yield in JavaScript and Node.js, but having an issue.
Ideally, what I'd want to do is wrap fs.readFile with generators/yield, so that I can use it synchronously without blocking anything.
I've come up with the following code:
function readFileSync (path) {
return (function *(){
return yield require('fs').readFile(path, function *(err, data){
yield data;
});
})();
}
console.log(readFileSync('test-file.txt'));
But, unfortunately, readFileSync
just always returns {}
instead of the file content.
Hopefully what I want to achieve is still possible, or perhaps I've completely missed the point of generators/yield and I'm using it entirely incorrectly, in which case pointing out where I've gone wrong and any resources would be great.
The yield keyword pauses generator function execution and the value of the expression following the yield keyword is returned to the generator's caller. It can be thought of as a generator-based version of the return keyword. yield can only be called directly from the generator function that contains it.
The yield keyword allows you to pause and resume a generator function ( function* ). In this syntax: The expression specifies the value to return from a generator function via the iteration protocol. If you omit the expression , the yield returns undefined .
readFile() Method. Parameters: The method accept three parameters as mentioned above and described below: filename: It holds the name of the file to read or the entire path if stored at other location. encoding: It holds the encoding of file.
Returns the contents of the file named filename. If encoding is specified then this function returns a string. Otherwise it returns a buffer.
How about using node with harmony features enabled (node --harmony
) and this super simple ES6 snippet :
function run( gen, iter) {
(iter=gen( (err, data) => (err && iter.raise(err)) || iter.next(data))).next();
}
run(function* (resume) {
var contents = yield require('fs').readFile(path, resume);
console.log(contents);
});
You can read more about this dead simple pattern (and try it out online) at this article at orangevolt.blogspot.com
Just a bit desugerifying and update (seems raise
is renamed to throw
) lgersman's answer to make it work with io.js 1.0.4:
function run(gen) {
var iter = gen(function (err, data) {
if (err) { iter.throw(err); }
return iter.next(data);
});
iter.next();
}
run(function* (resume) {
var contents = yield require('fs').readFile(path, resume);
console.log(contents);
});
Thank you lgersman!
You can use a helper lib like Wait.for-ES6 (I'm the author)
Pro's: You can call sequentially any standard async node.js function
Con's: You can only do it inside a generator function*
Example using fs.readdir
and fs.readfile
(both are standard async node.js functions)
var wait=require('wait.for-es6'), fs=require('fs');
function* sequentialTask(){
var list = yield wait.for(fs.readdir,'/home/lucio');
console.log(list); // An array of files
var data = yield wait.for(fs.readFile,list[0]); //read first file
console.log(data); // contents
}
wait.launchFiber(sequentialTask);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With