0

我根本想不通。我有一个包含文件的文件夹。我想用这些文件的信息创建一个 json。准确地说是文件名、文件名的正则表达式版本以及我从 ajax 调用中获得的其他数据。

各个部分工作完美。事实上,如果我同步运行我的代码,我会得到我想要的结果。像这样的东西:

 [
          { 
              "filename" : "first file",
              "regexname" : "first file",
              "ajaxresult" : "first file"
          },
          { 
              "filename" : "second file",
              "regexname" : "second file",
              "ajaxresult" : "second file"
          },
 ]

但是我想异步执行它,因为我使用的 XHR 模块在尝试“同步”执行所有操作时无法正常工作,而且它当然会阻塞,尤其是在处理大量文件时。我的“同步”代码看起来像这样(稍微简化以使其更短)

  fs.readdir(datapath, function(err, files) { 
    var data = new Array();
        if(err) throw err;
        files.forEach(function(file){
            var filename = file
            , regex= filename.replace(/regex/)/i, "")
            , filepath = './public/config/dataconfig.js'
            , ajaxResults = getFile(url)
            , mapFiles = null

        mapFiles = { filename:filename, regexname:regex, ajaxcall:ajaxResults}
        data[data.length] = mapfiles;
    }
    var JSONdata= JSON.stringify(data, null, 4);
    fs.writeFile(filepath, JSONdata, function(e) {
        if (!e) {
            console.log('Done')
        }else{ 
            console.log('Failed', e)   
        };
    });
 });

我尝试将 ajaxcall 包装在一个承诺中,但我在承诺中丢失了文件名和正则表达式名。像这样:

  fs.readdir(datapath, function(err, files) { 
    var data = new Array();
        if(err) throw err;
        files.forEach(function(file){
            var filename = file
            , regex= filename.replace(/regex/)/i, "")
            , filepath = './public/config/dataconfig.js'
            , mapFiles = null

        // Make promise for async call with a url composed of the regex
        var promise = getFile(url);
        promise.then( function(result) {
             mapFiles = { filename:filename, regexname:regex, ajaxcall:result}
             data[data.length] = mapfiles;
                 var JSONdata= JSON.stringify(data, null, 4);
                 fs.writeFile(filepath, JSONdata, function(e) {
                    if (!e) {
                          console.log('Done')
                     }else{ 
                          console.log('Failed', e)   
                     };
                  });
            }); 
  });

这给了我以下结果:

 [
          { 
              "filename" : "first file",
              "regexname" : "first file",
              "ajaxresult" : "first file"
          },
          { 
              "filename" : "first file",
              "regexname" : "first file",
              "ajaxresult" : "second file"
          },
 ]

所以我最后的想法是为节点使用类似异步模块的东西。在我从函数返回回调后编写 json。但我也无法让它发挥作用。

提前致谢!

[编辑-我忘了提]

我忘了提到的是 AjaxCall url 是用正则表达式构建的。所以是这样的:

      url = 'http://www.test.com/'+regex

所以这(如我所见)意味着我在调用 ajaxcall 之前执行正则表达式,但在调用之后我还需要正则表达式以写入 Json。我希望这是有道理的

[编辑 2 - 更多信息]

我的 XHR 调用看起来像这样(没有我错误的承诺解决方案。在这种情况下,我返回承诺的结果):

// Get info
function getFile(url) { 
    xhr = new XMLHttpRequest(); 
    xhr.open("GET", url); 
    xhr.onreadystatechange = handler
    var ajaxResult = null
    //Callback
    function handler (){
        // If status is ready
        if (this.readyState == 4 && this.status == 200) {
            ajaxResult = eval(this.responseText);
            console.log('XHR OK')
        };
    };
    xhr.send(null);
    return ajaxResult[0];
};
4

3 回答 3

1

正如您所提到的,这是一个使用async的快速示例:

doStuffWithFiles('folder', 'output.json', function () {
  console.log('Done!');
});

function doStuffWithFiles (dirPath, outputFilePath, callback) {
  fs.readdir(dirPath, function (error, files) {
    async.map(
      files,
      function (file, callback) {
        doAjaxStuff(file, function (error, ajaxResults) {
          callback(null, {
            filename:    file,
            regexStuff:  file.replace(/stuff/, ''),
            ajaxResults: ajaxResults
          });
        });
      },
      function (error, results) {
        var data = JSON.stringify(results);
        fs.writeFile(outputFilePath, data, function (error) {
          callback();
        });
      }
    );
  });
}

关键部分async.map就像标准map函数一样,除了它要求您将结果作为参数返回给传递给您的第一个函数的回调。一旦所有回调都返回,async.map调用第二个函数,将结果列表传递给它。

于 2013-02-14T20:46:02.343 回答
1

基于 Promise 的解决方案可以正常工作,可能如下所示:

readdir(datapath).map(function (file) {
  return getFile(url)(function (ajaxresult) {
    return writeFile('./public/config/dataconfig.js', JSON.stringifiy({
      filename: file,
      regexname: file.replace(/regex/i, ""),
      ajaxcall: ajaxResult
    }, null, 4));
  });
}).end(function () {
  console.log("All done");
}, function (e) {
  console.log("Failed", e);
});

在这个例子中,我使用了延迟承诺实现,为了让它工作,你需要确保所有异步函数都返回承诺。使用 deferred.promisify 可以轻松转换典型的回调函数:

var promisify = require('deferred').promisify;
var readdir = promisify(fs.readdir);
var writeFile = promisify(fs.writeFile);
于 2013-02-15T08:21:08.323 回答
0

如果您的问题是获取文件名和正则表达式,如何将它们绑定到您的回调,例如

var callback = function(result) {
         mapFiles = { filename:this.filename, regexname:this.regex, ajaxcall:result}
         data[data.length] = mapfiles;
             var JSONdata= JSON.stringify(data, null, 4);
             fs.writeFile(filepath, JSONdata, function(e) {
                if (!e) {
                 console.log('Done')
                 }else{ 
                  console.log('Failed', e)   
                 };
              }

然后

promise.then(callback.bind({'filename':filename,'regex':regex}))
于 2013-02-14T20:38:31.743 回答