Node.JS中如何判断递归嵌套的所有回调函数已经执行完毕,以读取目录下所有文件为例:计数比Promise方式快将近一倍

Promise 方法

Promise有一个 all 方法:

var fs        = require('fs');
var readdir   = promisify(fs.readdir);
var stat      = promisify(fs.stat);
var readFile  = promisify(fs.readFile);

// 简单实现一个promisify
function promisify(fn) {
  return function() {
    var args = arguments;
    return new Promise(function(resolve, reject) {
      [].push.call(args, function(err, result) {
        if(err) {
          console.log(err)
          reject(err);
        }else {
          resolve(result);
        }
      });
      fn.apply(null, args);
    });
  }
}

function readDirRecur(file, callback) {
  return readdir(file).then((files) => {
    files = files.map((item) => {
      var fullPath = file + '/' + item;

      return stat(fullPath).then((stats) => {
          if (stats.isDirectory()) {
              return readDirRecur(fullPath, callback);
          } else {
            /*not use ignore files*/
            if(item[0] == '.'){
              //console.log(item + ' is a hide file.');
            } else {
              callback && callback(fullPath)
            }
          }
        })
    });
    return Promise.all(files);
  });
}

var fileList = []

var timeStart = new Date()

readDirRecur('D:/github/oncedoc', function(filePath) {
  fileList.push(filePath)
}).then(function() {
  console.log('done', new Date() - timeStart);
  console.log(fileList);
}).catch(function(err) {
  console.log(err);
});

计数方法:

计数是比较常用的一种方法,其原理类似于c/c++中的引用计数,实现起来比较容易:

var fs        = require('fs');

function readDirRecur(folder, callback) {
  fs.readdir(folder, function(err, files) {
    var count = 0
    var checkEnd = function() {
      ++count == files.length && callback()
    }

    files.forEach(function(file) {
      var fullPath = folder + '/' + file;

      fs.stat(fullPath, function(err, stats) {
        if (stats.isDirectory()) {
            return readDirRecur(fullPath, checkEnd);
        } else {
          /*not use ignore files*/
          if(file[0] == '.') {

          } else {
            fileList.push(fullPath)            
          }
          checkEnd()
        }
      })
    })

    //为空时直接回调
    files.length === 0 && callback()
  })
}

var fileList  = []
var timeStart = new Date()

readDirRecur('D:/github/oncedoc', function(filePath) {
  console.log('done', new Date() - timeStart);
  console.log(fileList);
})

测试结果比较:
Promise法,耗时 6.2 秒 左右

$ node test.promise.js
done 6214
[ ...
  ... 55621 more items ]

计数法,耗时 3.5秒左右

$ node test.count.js
done 3590
[ ...
  ... 55621 more items ]

由此可见,计数法比Promise快将近1倍左右。

你可能感兴趣的:(Node.JS中如何判断递归嵌套的所有回调函数已经执行完毕,以读取目录下所有文件为例:计数比Promise方式快将近一倍)