Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/379.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 用fs模块理解节点JS生成器_Javascript_Node.js_Asynchronous_Generator_Ecmascript 6 - Fatal编程技术网

Javascript 用fs模块理解节点JS生成器

Javascript 用fs模块理解节点JS生成器,javascript,node.js,asynchronous,generator,ecmascript-6,Javascript,Node.js,Asynchronous,Generator,Ecmascript 6,有一段时间我对NodeJS非常兴奋。最后,我决定投入工作,编写一个测试项目,以了解Node最新和谐构建中的生成器 下面是我非常简单的测试项目: 要运行我的测试项目,您可以轻松地从Github中提取文件,然后使用以下工具运行它: node --harmony App.js 这是我的问题——我似乎无法让节点的异步fs.readdir方法与生成器内联运行。其他的项目,比如和似乎能够做到这一点 下面是我需要修复的代码块。我希望能够实例化FileSystem类型的对象并对其调用.list()方法:

有一段时间我对NodeJS非常兴奋。最后,我决定投入工作,编写一个测试项目,以了解Node最新和谐构建中的生成器

下面是我非常简单的测试项目:

要运行我的测试项目,您可以轻松地从Github中提取文件,然后使用以下工具运行它:

node --harmony App.js
这是我的问题——我似乎无法让节点的异步fs.readdir方法与生成器内联运行。其他的项目,比如和似乎能够做到这一点

下面是我需要修复的代码块。我希望能够实例化FileSystem类型的对象并对其调用.list()方法:

我需要提前做些什么才能将节点的fs.readdir转换成生成器吗

一个重要的注意事项是,我正在解析所有创建的类函数。这使我能够以不同于正常功能的方式处理生成器功能:

我真的被这个项目难倒了。希望得到任何帮助

以下是我试图实现的目标:

  • 通过John Resig的JavaScript类继承支持的修改版本大量使用类
  • 使用生成器获得对节点的stock异步调用的内联支持
  • 编辑 我试图实现您的示例函数,但遇到了一些问题

    list: function*(path) {
        var list = null;
    
        var whatDoesCoReturn = co(function*() {
            list = yield readdir(path);
            console.log(list); // This shows an array of files (good!)
            return list; // Just my guess that co should get this back, it doesn't
        })();
        console.log(whatDoesCoReturn); // This returns undefined (sad times)
    
        // I need to use `list` right here
    
        return list; // This returns as null
    }
    

    首先也是最重要的一点是,在你的头脑中有一个好的模型,准确地知道发电机是什么。generator函数是一个返回generator对象的函数,该generator对象将单步执行
    生成generator函数中的
    .next()
    语句

    根据该描述,您应该注意到没有提到异步行为。发电机自身的任何动作都是同步的。您可以立即运行到第一个
    yield
    ,然后执行
    setTimeout
    ,然后调用
    .next()
    转到下一个
    yield
    ,但导致异步行为的是
    setTimeout
    ,而不是生成器本身

    因此,让我们根据
    fs.readdir
    来分析这一点
    fs.readdir
    是一个异步函数,单独在生成器中使用它不会产生任何效果。让我们看一下您的示例:

    function * read(path){
        return yield fs.readdir(path);
    }
    
    var gen = read(path);
    // gen is now a generator object.
    
    var first = gen.next();
    // This is equivalent to first = fs.readdir(path);
    // Which means first === undefined since fs.readdir returns nothing.
    
    var final = gen.next();
    // This is equivalent to final = undefined;
    // Because you are returning the result of 'yield', and that is the value passed
    // into .next(), and you are not passing anything to it.
    
    希望它能让您更清楚,您仍然在同步调用
    readdir
    ,并且您没有传递任何回调,因此它可能会抛出错误或其他东西

    那么,如何从生成器中获得良好的行为呢? 通常,这是通过让生成器在实际计算值之前生成一个表示
    readdir
    结果的特殊对象来实现的

    例如,(不现实的),
    yield
    ing函数是一种生成表示值的内容的简单方法

    function * read(path){
        return yield function(callback){
            fs.readdir(path, callback);
        };
    }
    
    var gen = read(path);
    // gen is now a generator object.
    
    var first = gen.next();
    // This is equivalent to first = function(callback){ ... };
    
    // Trigger the callback to calculate the value here.
    first(function(err, dir){
      var dirData = gen.next(dir);
      // This will just return 'dir' since we are directly returning the yielded value.
    
      // Do whatever.
    });
    
    实际上,您希望这种类型的逻辑继续调用生成器,直到所有
    yield
    调用完成,而不是对每个调用进行硬编码。不过要注意的是,现在生成器本身看起来是同步的,而
    read
    函数之外的所有内容都是超级通用的

    您需要某种生成器包装函数来处理这个屈服值过程,您的示例就是这样做的。另一个例子是

    “返回表示值的内容”方法的标准方法是返回a或a,因为像我这样返回函数有点难看

    使用
    thunk
    co
    库,您可以在不使用示例函数的情况下执行上述操作:

    var thunkify = require('thunkify');
    var co = require('co');
    var fs = require('fs');
    var readdir = thunkify(fs.readdir);
    
    co(function * (){
        // `readdir` will call the node function, and return a thunk representing the
        // directory, which is then `yield`ed to `co`, which will wait for the data
        // to be ready, and then it will start the generator again, passing the value
        // as the result of the `yield`.
        var dirData = yield readdir(path, callback);
    
        // Do whatever.
    })(function(err, result){
        // This callback is called once the synchronous-looking generator has returned.
        // or thrown an exception.
    });
    
    更新 你的更新仍然有些混乱。如果你想让你的
    list
    函数成为一个生成器,那么无论你在哪里调用它,你都需要在
    list
    之外使用
    co
    co
    内部的所有内容都应基于生成器,而
    co
    外部的所有内容都应基于回调<代码>合作
    不会使
    列表
    自动异步
    co
    用于将基于生成器的异步流控制转换为基于回调的流控制

    e、 g


    @loganfsmyth已经为你的问题提供了答案。我的回答的目的是帮助您了解JavaScript生成器实际上是如何工作的,因为这是正确使用它们的一个非常重要的步骤

    生成器实现了一个新的概念,这个概念本身并不新鲜。新的是生成器允许使用熟悉的JavaScript语言构造(例如,
    for
    if
    try/catch
    )来实现状态机,而不放弃线性代码流

    生成器最初的目标是生成数据序列,这与异步无关。例如:

    // with generator
    
    function* sequence()
    {
        var i = 0;
        while (i < 10)
            yield ++i * 2;
    }
    
    for (var j of sequence())
        console.log(j);
    
    // without generator
    
    function bulkySequence()
    {
        var i = 0;
        var nextStep = function() {
            if ( i >= 10 )
                return { value: undefined, done: true };
            return { value: ++i * 2, done: false };
        }
        return { next: nextStep };
    }
    
    for (var j of bulkySequence())
        console.log(j);
    
    最后,让我们创建一系列事件:

    function workAsync(doneCallback)
    {
        var worker = (function* () {
            // the timer callback drivers to the next step
            setTimeout(function() { 
                worker.next(); }, 1000);
    
            yield null;
            console.log("timer1 fired.");
    
            setTimeout(function() { 
                worker.next(); }, 2000);
    
            yield null;
            console.log("timer2 fired.");
    
            setTimeout(function() { 
                worker.next(); }, 3000);
    
            yield null;
            console.log("timer3 fired.");
    
            doneCallback(null, null);
        })();
    
        // initial step
        worker.next();
    }
    
    workAsync(function(err, result) { 
        console.log("Done, any errror: " + err); });
    

    一旦理解了这个概念,就可以继续使用承诺作为生成器的包装,这将使它进入下一个强大的级别

    你能试着删减你的例子并把它包括在问题中吗?您拥有的类逻辑与应用生成器无关,虽然我有一些建议,但现在很难给出答案。通常情况下,如果代码太大,无法放在问题的主体中,那么答案就太大,除了你之外,对任何人都没有帮助。@loganfsmyth我继续并更新了我的问题,以包含相关的代码。谢谢@KirkOuimet已损坏。
    //这相当于first=fs.readdir(path)
    我认为这里也将是
    未定义的
    ,因为
    fs.readdir(path)
    将在屈服之前进行计算。@thefourtheye Good call,我添加了一个注释。我试图让他的例子的映射变得明显,但我应该提到这一点。嗨@loganfsmyth-谢谢你花时间来帮助我!我试图实现您的示例函数,但遇到了一些问题。你能看一下并给我一些反馈吗@柯克更新了我的密码
    // with generator
    
    function* sequence()
    {
        var i = 0;
        while (i < 10)
            yield ++i * 2;
    }
    
    for (var j of sequence())
        console.log(j);
    
    // without generator
    
    function bulkySequence()
    {
        var i = 0;
        var nextStep = function() {
            if ( i >= 10 )
                return { value: undefined, done: true };
            return { value: ++i * 2, done: false };
        }
        return { next: nextStep };
    }
    
    for (var j of bulkySequence())
        console.log(j);
    
    function workAsync(doneCallback)
    {
        var worker = (function* () {
            // the timer callback drivers to the next step
            var interval = setInterval(function() { 
                worker.next(); }, 500);
    
            try {
                var tick = 0;
                while (tick < 10 ) {
                    // resume upon next tick
                    yield null;
                    console.log("tick: " + tick++);
                }
                doneCallback(null, null);
            }
            catch (ex) {
                doneCallback(ex, null);
            }
            finally {
                clearInterval(interval);
            }
        })();
    
        // initial step
        worker.next();
    }
    
    workAsync(function(err, result) { 
        console.log("Done, any errror: " + err); });
    
    function workAsync(doneCallback)
    {
        var worker = (function* () {
            // the timer callback drivers to the next step
            setTimeout(function() { 
                worker.next(); }, 1000);
    
            yield null;
            console.log("timer1 fired.");
    
            setTimeout(function() { 
                worker.next(); }, 2000);
    
            yield null;
            console.log("timer2 fired.");
    
            setTimeout(function() { 
                worker.next(); }, 3000);
    
            yield null;
            console.log("timer3 fired.");
    
            doneCallback(null, null);
        })();
    
        // initial step
        worker.next();
    }
    
    workAsync(function(err, result) { 
        console.log("Done, any errror: " + err); });