将fs.readFile包装在生成器/yield中

10

我正在努力理解JavaScript和Node.js中的生成器和yield,但遇到了问题。

理想情况下,我希望能够使用生成器/ yield来包装fs.readFile,以便我可以在不阻塞任何内容的情况下同步使用它。

我想出了以下代码:

function readFileSync (path) {
    return (function *(){
        return yield require('fs').readFile(path, function *(err, data){
            yield data;
        });
    })();
}

console.log(readFileSync('test-file.txt'));

但是,不幸的是,readFileSync总是返回{}而不是文件内容。

希望我想要实现的仍然是可能的,或者我完全误解了生成器/ yield 的重点,并且我完全使用不正确,在这种情况下,指出我错在哪里以及任何资源都将是很好的。


我看到的所有生成器示例都涉及到了 Promises。你的脚本是基于哪些文档/帖子/教程的? - Bergi
为什么不直接使用 fs.readFileSync - Bergi
1
为什么不直接使用fs.readFileSync呢?它是阻塞的。这里的用例是使这行代码变成非阻塞的:https://github.com/bevry/ssg-experiments/blob/aba629383d0945fffc843e2d43c4b180ca0083bd/index.js#L24 - balupton
我看到的所有生成器示例都涉及到了 Promises。你的脚本是基于哪些文档/帖子/教程的?没有具体的示例,因为没有一个完全符合我的要求,所以这只是我最好的猜测的混合体... - balupton
1
“同步”意味着“阻塞”。我认为这是不可能的,请查看如何在Node.js或Javascript中封装异步函数调用为同步函数 - Bergi
4个回答

10

使用启用了harmony特性的node (node --harmony) 和这个超级简单的ES6代码片段怎么样:

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

您可以在orangevolt.blogspot.com的文章中阅读更多有关这种极简模式的信息(并在线尝试它)。


2

稍微修改一下,并更新一下(似乎raise被重命名为throw)。lgersman的回答,使其可以在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);
});

感谢lgersman!

1
你可以使用类似Wait.for-ES6的辅助库(我是作者)。
优点:你可以顺序调用任何标准异步node.js函数。
缺点:你只能在生成器function*内部执行。
例如,使用fs.readdirfs.readfile(两者都是标准的异步node.js函数)。
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);

-3

使用生成器无法将异步函数转换为同步函数。

生成器可以中断自身,但无法中断其他函数的控制流程。

因此,您的代码能够正常工作的唯一方法是将其放置在另一个生成器内部:

console.log(yield* readFileSync('test-file.txt'));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接