循环中的节点 Grunt 异步任务,闭包不起作用

Posted

技术标签:

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

提前感谢您查看此内容。

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

    将我的循环变量“key”包装在一个闭包中以避免经典的“最后一个值” only”问题,其中循环在异步任务返回值之前很久就完成了,并且只显示最后一个值。 调用 done(error) 以完成我的异步任务(根据 Gruntjs 常见问题解答) 使用 hasOwnProperty() 确保键是对象的实际属性,而不是来自原型。 遵循 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

【问题讨论】:

【参考方案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

以上是关于循环中的节点 Grunt 异步任务,闭包不起作用的主要内容,如果未能解决你的问题,请参考以下文章

异步作用域闭包

前端知识体系:JavaScript基础-作用域和闭包-如何处理循环的异步操作

带有咕噜声的sass不起作用

SpringBoot异步任务及Async不起作用的原因

自定义异步任务的实现不起作用

9Python Asyncio异步编程-事件循环详解