在for循环中异步读取多个文件

时间:2017-08-03 13:01:07

标签: javascript file asynchronous

到目前为止,这是我的javascript代码:

文件是指向html文件的路径数组

我希望h3s成为html文件的所有h3s标签的数组。

function getH2OfFiles(files) {

  return new Promise((resolve, reject) => {
    let h3s = [];
    for (let i = 0; i < files.length; i++) {
      fs.readFile(path.join(__src, 'documentation', files[i]), 'utf8', (err, data) => {
        if (err) throw err;
        if (data.match(/<h3>(.*)<\/h3>/)) {
          //console.log("->", { file: files[i], h3: data.match(/<h3>(.*)<\/h3>/)[1] })
          h3s.push(data.match(/<h3>(.*)<\/h3>/)[1]);
        }
      })

    }
    resolve(h3s);
  });
}

它似乎不适用于for循环(因为它是异步的),但它是如何实现的?

3 个答案:

答案 0 :(得分:2)

承诺世界中ConfigurableApplicationContext循环的副本for,通常与Promise.all结合使用。在您的情况下,编写一个处理一个文件的函数,例如

.map

然后将其应用于文件列表:

function getH3OfFile(fileName) {
    return new Promise((resolve, reject) => {
        fs.readFile(path.join('.....', fileName), 'utf8', (err, data) => 
            err
                ? reject(err)
                : resolve(data.match(/<h3>(.*)<\/h3>/))
        );
    });
}

(万一你不知道,还有let fileNames = [...] Promise .all(fileNames.map(getH3OfFile)) .then(h3s => ...) // h3s is an array of matches )。

答案 1 :(得分:1)

你大部分时间都在那里,你只需要跟踪你已经获得了多少回调,并等待你解决这些问题。另外,如果出现问题,请使用reject(err)而不是throw err

function getH2OfFiles(files) {

  return new Promise((resolve, reject) => {
    let h3s = [];
    let complete = 0;
    for (let i = 0; i < files.length; i++) {
      fs.readFile(path.join(__src, 'documentation', files[i]), 'utf8', (err, data) => {
        if (err) reject(err);                       // ***
        const match = data.match(/<h3>(.*)<\/h3>/);
        if (match) {                                // ***
          h3s.push(match[1]);
        }
        if (++complete === files.length) {          // ***
          resolve(h3s);                             // ***
        }                                           // ***
      })
    }
  });
}

(请注意,我还将第一次调用的结果保存到match,而不是让正则表达式运行两次。)

但是,请注意您可以不按顺序接收这些完成,因此h3s可能与文件无关(如果重要)。

或者通过分而治之的方式进行简化并给自己一个承诺版本的readFile,然后通过Promise.all读取所有文件后构建结果:

function readFilePromise(path, encoding) {
  return new Promise((resolve, reject) => {
    fs.readFile(path, encoding, (err, data) => {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
  });
}

function getH2OfFiles(files) {
  return Promise.all(files.map(file => readFilePromise(path.join(__src, 'documentation', file), 'utf8')))
         .then(results => {
           const h3s = [];
           results.forEach(result => {
             const match = data.match(/<h3>(.*)<\/h3>/);
             if (match) {
               h3s.push(match[1]);
             }
           });
           return h3s;
         });
}

这也有一个好处,Promise.all可确保您以与原始承诺数组相同的顺序接收数组(如果重要)。

(注意:有些lib将为您提供Promise-ify NodeJS API。)

答案 2 :(得分:0)

使用async npm模块。它们提供同步迭代方法以及控制流的不同方法,如系列,瀑布,并行等。