Почему эта функция правильно возвращает данные, когда не используется вариант синхронизации ReadFile?

#node.js

#node.js

Вопрос:

Когда я вызываю этот код, который представляет собой попытку считывания файлов в каталоге в массив filename: content , он не запускает console.log(data) внутри вызова readFiles() . Если я использую ReadFile, он работает так, как ожидалось, но из-за потребностей синхронного выполнения это не дает данных при использовании вне вызова.

 function readFiles(parameters) {
    var dirname = parameters.dirname;
    var onFileContent = parameters.onFileContent;
    var onError = parameters.onError;
    fs.readdir(dirname, (err, filenames)=>{
        if (err) {
            onError(err);
            return;
        }
        filenames.forEach(filename => {
             return fs.readFileSync(path.resolve(dirname, filename), 'utf-8', {stdio: [0, 1, 2]}, (err, content)=>{
                if (err) {
                    onError(err);
                    return;
                }
                onFileContent(filename, content);
            });
        });
    });
};


readFiles({
        dirname: path.join(__dirname, '../ping/'), onFileContent: (filename, content) => {
            data[filename] = content;
            //console.log(content);
            //global.data2 = data;
            console.log(data);
        }, onError: function (error) {
            console.log(error);

        }
    });
console.log(data);
  

При использовании варианта синхронизации мне просто предоставляется {}, но async выдает:

 { test_node: '{"changed": false, "ping": "pong"}' }
  

{ test_node: ‘{«изменено»: false, «ping»: «pong»}’,
test_node_2: ‘{«изменено»: false, «ping»: «pong»}’ }

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

Комментарии:

1. Когда вы вызываете readFileSync, параметра обратного вызова нет, вы просто получаете результат в качестве возвращаемого значения. nodejs.org/api/fs.html#fs_fs_readfilesync_file_options

2. Как именно я должен это реализовать? Я пробовал добавлять в оператор return, но без кубиков.

3. readFileSync не вызывает cb, поэтому onFileContent никогда не вызывается

4. Я совершенно не уверен, как изменить свой код, чтобы не использовать обратный вызов, есть ли у вас какие-либо советы о том, что мне нужно сделать?

5. Я чувствую, что если бы я использовал promises, я мог бы использовать то, что у меня есть, но я никогда не пытался использовать их раньше.

Ответ №1:

Вот полностью синхронная версия того, что, я думаю, вы ищете:

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

function readFiles(dir) {
    var files = {};

    fs.readdirSync(dir)
        .forEach(name => {
            if (fs.statSync(path.join(dir, name)).isDirectory()) return;

            files[name] = fs.readFileSync(path.join(dir, name), 'utf8');
        });

    return files;
}

var files = readFiles('/some/folder');

console.log(files);
  

Комментарии:

1. Это решение, большое вам спасибо. Это помогло мне лучше понять синхронизацию, чем я.

Ответ №2:

Поскольку вы используете readFileSync, ваш код становится несколько проще в написании, потому что вам не придется иметь дело с его асинхронностью (у вас все еще есть некоторая асинхронность из readdir, но, по крайней мере, у вас на один уровень меньше поводов для беспокойства).

Вот как это может выглядеть:

     function readFiles(parameters) {
      var dirname = parameters.dirname;
      var onFileContent = parameters.onFileContent;
      var onError = parameters.onError;
      fs.readdir(dirname, (err, filenames)=>{
        if (err) {
          onError(err);
          return;
        }
        filenames.forEach(filename => {
          var resu<
          try {
            result = fs.readFileSync(path.resolve(dirname, filename), 'utf-8', {stdio: [0, 1, 2]});
          } catch(err) {
            // we need to catch the errors synchronously too, so use a plain catch 
            // statement for this
            onError(err);
            return;
          }
          onFileContent(filename, result);
        });
      });
    }
  

Кстати, я не уверен, что вам это , {stdio: [0, 1, 2]} тоже нужно (я не знаком с этим параметром и не видел его в документе)

Комментарии:

1. Хммм, это ближе, но я все еще не могу получить данные в массив данных.

2. Итак, как вы ее вызываете, важно знать, что ваш console.log вызов сразу после вызова функции ничего не вернет, потому что он выполняется до обратного вызова. Вы получите данные только внутри обратного вызова. Если вы не уверены, что readdir должен быть асинхронным, вам следует посмотреть на ответ Джеффа Макклауда, потому что это полностью синхронизированное решение, поэтому у него нет обратного вызова.