使用for循环转换回调并将递归转换为promises

时间:2017-06-02 04:19:24

标签: javascript node.js callback promise es6-promise

我编写了一个递归运行的函数来查找名称包含给定世界的文件。我不明白承诺是如何运作的,尽管努力了,但是找不到用承诺写这个函数的方法。

我尝试在findPath函数中返回一个promise但由于extractFiles调用了findPath,我无法使用它。我试图创建一份承诺清单并返回所有承诺但不能成功。

那我怎么能用promises写这些函数呢?

const fs   = require('fs');
const path = require('path');


function findPath(targetPath, targetWord, done) {
  if (!fs.existsSync(targetPath)) return;

  fs.readdir(targetPath, (err, allPaths) => {
    if (err) done(err, null);

    for (aPath of allPaths) {
      aPath = path.join(targetPath, aPath);
      extractFiles(aPath, targetWord, done);
    }
  });

  function extractFiles(aPath, targetWord, done) {
    fs.lstat(aPath, (err, stat) => {
      if (err) done(err, null);

      if (stat.isDirectory()) {
        findPath(aPath, targetWord, done);
      }
      else if (aPath.indexOf(targetWord) >= 0) {
        let fileName = aPath.split('.')[0];
        done(null, fileName);
      }
    });
  }
}

findPath('../modules', 'routes', file => {
  console.log(file);
});

1 个答案:

答案 0 :(得分:0)

首先,为了使“核心”代码更具可读性,我将宣传fs函数

const promisify1p = fn => p1 => new Promise((resolve, reject) => {
    fn(p1, (err, result) => {
        if(err) {
            reject(err);
        } else {
            resolve(result);
        }
    });
});
const readdirAsync = promisify1p(fs.readdir);
const lstatAsync = promisify1p(fs.lstat);

然后,就像你对任何其他承诺一样链接承诺

const fs = require('fs');
const path = require('path');

function findPath(targetPath, targetWord) {
    const readPath = target => 
        readdirAsync(target)
        .then(allPaths => 
            Promise.all(allPaths.map(aPath => extractFiles(path.join(target, aPath))))
            .then(x => x.filter(x=>x)) // remove all the "false" entries - i.e. that don't match targetWord
            .then(x => [].concat.apply([], x)) // flatten the result
        );
    const extractFiles = aPath =>
        lstatAsync(aPath).then(stat => {
            if (stat.isDirectory()) {
                return readPath(aPath);
            } else if (aPath.includes(targetWord)) {
                return aPath.split('.')[0];
            }
            return false;
        });
    return readPath(targetPath);
}

findPath('../modules', 'routes')
.then(results => {
    // do things with the results - which is an array of files that contain the targetWord
})
.catch(err => console.error(err));

根本不多。