Node.js отправляет нулевые данные об обратном вызове - PullRequest
0 голосов
/ 02 января 2019

есть функция, которую я использую для чтения всех файлов в каталоге, а затем отправляю объект с эмиттером клиенту.

это мой код, который отлично работает,

const getFilesList = (path, emitter) => {
  fs.readdir(path, (err, files) => {
    emitter('getFileList', files);
  });
};

но когда я хочу отфильтровать скрытые файлы с помощью этого кода, «стандартные папки» будут отправлять пустые данные в эмиттере.

const getFilesList = (path, emitter) => {
  let standardFolders = [];
  fs.readdir(path, (err, files) => {
    if (files) {
      files.map((file) => {
        winattr.get(path + file, function (err, attrs) {
          if (err == null && attrs.directory && (!attrs.hidden && !attrs.system)) {
            standardFolders.push(file)
          }
        });
      });
    } else {
      standardFolders = null;
    }
    emitter('getFileList', standardFolders);
  });
};

что не так с моим кодом во второй части?

Ответы [ 2 ]

0 голосов
/ 02 января 2019

Как уже сказано в другом ответе winattr.get является асинхронным, поэтому цикл завершается до вызова любого из обратных вызовов winattr.get.

Вы можете преобразовать свой код, используя async / await и primitify, в код, похожий на версию синхронизации, и вы можете полностью избавиться от обратных вызовов или счетчиков

const {promisify} = require('util')

const readdir = promisify(require('fs').readdir)
const winattrget = promisify(require('winattr').get)

const getFilesList = async (path, emitter) => {
  let standardFolders = [];

  try {
    let files = await readdir(path);

    for (let file of files) {
      try {
        let attrs = await winattrget(path + file)

        if (attrs.directory && (!attrs.hidden && !attrs.system)) {
          standardFolders.push(file)
        }
      } catch (err) {
        // do nothing if an error occurs
      }
    }

  } catch (err) {
    standardFolders = null;
  }

  emitter('getFileList', standardFolders);
};

Дополнительное примечание: в вашем коде вы пишете files.map, но отображение используется для преобразования значений данного массива и сохранения их в новом, а в текущем коде это не делается, поэтому в заданном В этом случае вам следует использовать цикл forEach вместо map.

0 голосов
/ 02 января 2019

winattr.get(filepath,callback) является асинхронным, поэтому представьте, что ваш код «запускает» строку file.map(), а затем сразу же переходит к emitter('getFileList',standardFolders) --- который standardFolders пуст, поскольку он еще не завершен!

Вы можете использовать библиотеку, такую ​​как async.io, для обработки ваших функций обратного вызова, или вы можете использовать счетчик и отслеживать, когда все обратные вызовы (для каждого файла) завершены самостоятельно.

Пример:

// an asynchronous function because setTimeout
function processor(v,cb){
  let delay = Math.random()*2000+500;
  console.log('delay',delay);
  setTimeout(function(){
    console.log('val',v);
    cb(null,v);
  },delay);
  
}
const main = function(){
  const list = ['a','b','c','d'];
  let processed = [];
  let count = 0;
  console.log('starting');
  list.map(function(v,i,a){
    console.log('calling processor');
    processor(v,function(err,value){
      processed.push(v);
      count+=1;
      console.log('count',count);
      if(count>=list.length){
        // all are finished, continue on here. 
        console.log('done');
      }
    })
  })
  console.log('not done yet!');
};
main();

Аналогично для вашего кода:

const getFilesList = (path, emitter) => {
  let standardFolders = [];
  fs.readdir(path, (err, files) => {
    if (files) {
      let count = 0;
      files.map((file) => {
        winattr.get(path + file, function (err, attrs) {
          if (err == null && attrs.directory && (!attrs.hidden && !attrs.system)) {
            standardFolders.push(file)
          }
          count+=1;
          if(count>=files.length){
            // finally done
            emitter('getFileList', standardFolders);
          }
        });
      });
    } else {
      standardFolders = null;
      emitter('getFileList', standardFolders);
    }

  });
};
...