Nodejs:如何异步处理带有文件内容的String.replace?

时间:2017-03-18 02:46:42

标签: javascript node.js

这是我正在尝试做的事情。

var data = data.replace(/{{(.*?)}}/g, function (a, b) {
    if (fs.existsSync("./include" + b)) {
        return new String(fs.readFileSync('./include' + b));
    } else {
        console.log("ERROR!: ./include" + a + " not found.");
        return "";
    }
});

代码完美无缺。但是,existsSync和readFileSync将阻止节点进程。

我无法在手前缓冲所有文件,因为它太大并且消耗大量内存。

我正在看诺言,但不是.then()会阻止线程吗?

在这种情况下有没有办法使用fs.readFile?

3 个答案:

答案 0 :(得分:0)

您可能想要使用readFile代替,也可以使用错误返回检查文件是否存在

data.replace(/{{(.*?)}}/g, function (a, b) {
  fs.readFile('./include' + b, (err, fileData) => {
      if (err) {
        console.log(err);
        return;
      }

      data = new String(fileData)
  })
});

答案 1 :(得分:0)

您可以选择exist()readFile的异步功能。但是,existdeprecated。建议改用accessstat

var data = data.replace(/{{(.*?)}}/g, function (a, b) {

    fs.access("./include" + b, function(err) {
        if (err) {
        // specific "no such file or directory" error code
            if (err.code === 'ENOENT')
                return console.log("ERROR!: ./include" + a + " not found.");
            // throw another error as well          
            throw err;
        }

        fs.readFile('./include' + b, "utf-8", function(err, data) {
            if (err)
                // handle error
            return data;
        });
    });
});

但是,如上所述,也不建议这样做。

  

使用fs.access()检查之前文件的可访问性   不建议调用fs.open(),fs.readFile()或fs.writeFile()。   这样做会引入竞争条件,因为其他过程可能会发生变化   两个调用之间的文件状态。相反,用户代码应该   直接打开/读/写文件并处理引发的错误   文件无法访问。

作为建议,我们的代码可以修改为:

var data = data.replace(/{{(.*?)}}/g, function (a, b) {

    fs.readFile('./include' + b, "utf-8", function(err, data) {
        if (err) {
            if (err.code === 'ENOENT')
                return console.log("ERROR!: ./include" + a + " not found.");
            throw err;
        }   
        return data;
    });
});

答案 2 :(得分:0)

我建议不要在单个功能中尝试这样做。细分你需要做的事情,特别是涉及异步时。

const fs = require('fs');

// find a list of unique file references
function findFiles (data) {
  const files = {};
  const regex = /{{(.*?)}}/g;
  while ((match = regex.exec(data)) != null) {
    files[match[1]] = true;
  }
  return Object.keys(files);
}

function replaceFile (data, filePath) {
  return new Promise((resolve, reject) => {
    fs.readFile(`./include${filePath}`, function (err, fileData) {
      if (err) {
        console.log(err);
        return resolve(data);
      }
      // we can replace multiple file references without reading
      // the file multiple times.
      const regex = new RegExp('{{' + filePath + '}}', 'g');
      return resolve(data.replace(regex, fileData));
    });
  });
}

// use of reduce to allow us to chain the promises so we modify
// data one file at a time and don't rely on it bing a reference
// which we're modifying.
function replaceFiles (data, filePaths) {
  return filePaths.reduce(
    (promise, filePath) => {
      return promise.then((newData) => {
        return replaceFile(newData, filePath);
      });
    },
    Promise.resolve(data)
  );
}

const data = 'hello {{/file.txt}} {{/file2.txt}} {{/file.txt}} world';

const filePaths = findFiles(data);
console.log({ filePaths });

replaceFiles(data, filePaths)
.then(data => console.log({ data }));