【问题标题】:Node Grunt Asynchronous Task in Loop with Closure not Working循环中的节点 Grunt 异步任务,闭包不起作用
【发布时间】:2013-01-02 16:38:33
【问题描述】:

提前感谢您查看此内容。

我在一个不工作的循环中有一个异步任务。我已经确保:

  1. 将我的循环变量“key”包装在一个闭包中以避免经典的“最后一个值” only”问题,其中循环在异步任务返回值之前很久就完成了,并且只显示最后一个值。
  2. 调用 done(error) 以完成我的异步任务(根据 Gruntjs 常见问题解答)
  3. 使用 hasOwnProperty() 确保键是对象的实际属性,而不是来自原型。
  4. 遵循 node.exec 示例的格式,除了将 exec 的值分配给一个变量——我已经尝试过,但没有帮助。请参阅下面的第一个参考。

这个函数输出......什么都没有!?由于某种原因, grunt.log.writeln 语句甚至没有触发。任务完成没有错误。我还尝试添加 20 秒的延迟,以防脚本在异步任务返回之前完成。奇怪的是,如果我不调用“done(error)”,文件会被写入文件(当我用 grunt.file.write 语句替换 writeln 时)。

var done = this.async(),
    exec = require('child_process').exec,
    myJSON = {
      "file1" : "C:/home/me/jquery.js",
      "file2 " : "C:/home/me/grunt.js",
      ...
      "fileN" : "C:/home/me/N.js"
    },
    count;

for (var key in myJSON) {
    if (myJSON.hasOwnProperty(key)) {
      (function (key) { 
        exec( 'type "' + myJSON[key] + '"', 
          function(error, stdout, stderr) {
            if (error) {
                grunt.log.writeln('!!! exec error: ' + error);
            }
            grunt.log.writeln('stdout: ' + stdout);
            grunt.log.writeln('stderr: ' + stderr);
            done(error);
          }
        );
      })(key);
    count++;
  }
}

参考资料:

http://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback https://github.com/gruntjs/grunt/wiki/Frequently-Asked-Questions

【问题讨论】:

    标签: node.js asynchronous callback closures gruntjs


    【解决方案1】:

    done() 应该只在整个操作完成时调用,这意味着当所有exec() 方法都运行了它们的回调时。目前,您正在每次迭代中执行 done 回调。您可以通过使用 grunt 附带的节点模块 async 中的 forEach 方法轻松实现此目的(grunt.util.async(,如果您希望按顺序执行 exec() 方法,则为 forEachSeries

    类似这样的东西(未测试):

    var done = this.async();
    var exec = require('child_process').exec;
    var async = grunt.util.async; // updated
    var myJSON = {
      "file1": "C:/home/me/jquery.js",
      "file2": "C:/home/me/grunt.js",
      ...
      "fileN": "C:/home/me/N.js"
    };
    
    async.forEach(Object.keys(myJSON), function(el, cb) {
      exec('type "' + myJSON[el] + '"', function(error, stdout, stderr) {
          if (error) {
              grunt.warn('!!! exec error: ' + error)
              return cb(error);
          }
          grunt.log.writeln('stdout: ' + stdout);
          grunt.log.writeln('stderr: ' + stderr);
          cb();
        }
      );
    }, function(error) {
      done(!error);
    });
    

    【讨论】:

    • tyvm。常见问题解答让我相信 done() 必须为任务中的每个异步操作调用。这是一个很大的帮助。我很感激你的时间。 :)。
    • 所以,这里的要点是 grunt.utils.async 实用程序更适合处理异步任务——而不是手动创建闭包等,对吗?
    • 这是正确的,但不仅仅是咕噜声。一般来说,在 Node.js 中工作时,它是无价的。 github.com/caolan/async
    • @SindreSorhus 对您调用 grunt.task.run('asynctaskname:asynctarget') 而不是 exec() 的实例有任何建议吗?在这种情况下,存在一种异步冲突,因为循环产生了一堆异步任务 - 并且任务的异步“完成”没有连接到 async.forEach
    • grunt.util.async 现已弃用,但可以替换为npmjs.com/package/async
    猜你喜欢
    • 2017-09-30
    • 1970-01-01
    • 1970-01-01
    • 2015-08-26
    • 1970-01-01
    • 2014-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多