Как правильно читать файл с помощью async/await?

Я не могу понять, как работает async/await. Я немного понимаю, но не могу заставить это работать.

function loadMonoCounter() {
    fs.readFileSync("monolitic.txt", "binary", async function(err, data) {
       return await new Buffer( data);
  });
}

module.exports.read = function() {
  console.log(loadMonoCounter());
};

Я знаю, что могу использовать readFileSync, но если я это сделаю, я знаю, что никогда не пойму async/await, и я просто решу проблему.

Цель: вызвать loadMonoCounter() и вернуть содержимое файла.

Этот файл увеличивается каждый раз при вызове incrementMonoCounter() (при каждой загрузке страницы). Файл содержит дамп буфера в двоичном виде и хранится на SSD.

Независимо от того, что я делаю, я получаю сообщение об ошибке или неопределенное в консоли.

13 ответов

Решение

Использовать await / async вам нужны методы, которые возвращают обещания. Основные функции API не делают этого без таких оболочек, как promisify:

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

// Convert fs.readFile into Promise version of same    
const readFile = util.promisify(fs.readFile);

async function getStuff() {
  return await readFile('test');
}

// Can't use `await` outside of an async function so you need to chain
// with then()
getStuff().then(data => {
  console.log(data);
})

Как примечание, readFileSync не принимает обратный вызов, возвращает данные или создает исключение. Вы не получаете желаемое значение, потому что та функция, которую вы предоставляете, игнорируется и вы не фиксируете фактическое возвращаемое значение.

Поскольку Node v11.0.0 fs promises изначально доступен без promisify:

const fs = require('fs').promises;
async function loadMonoCounter() {
    const data = await fs.readFile("monolitic.txt", "binary");
    return new Buffer(data);
}

Это TypeScript-версия ответа @Joel. Его можно использовать после Node 11.0:

import { promises as fs } from 'fs';

async function loadMonoCounter() {
    const data = await fs.readFile('monolitic.txt', 'binary');
    return Buffer.from(data);
}

Вы можете использовать fs.promises доступно изначально, начиная с Node v11.0.0

import fs from 'fs';

const readFile = async filePath => {
  try {
    const data = await fs.promises.readFile(filePath, 'utf8')
    return data
  }
  catch(err) {
    console.log(err)
  }
}

Вы можете легко обернуть команду readFile таким обещанием:

async function readFile(path) {
    return new Promise((resolve, reject) => {
      fs.readFile(path, 'utf8', function (err, data) {
        if (err) {
          reject(err);
        }
        resolve(data);
      });
    });
  }

затем используйте:

await readFile("path/to/file");

С узла v14.0.0

      const {readFile} = require('fs/promises');

const myFunction = async()=>{
    const result = await readFile('monolitic.txt','binary')
    console.log(result)
}

myFunction()

Чтобы он оставался лаконичным и сохранял все функциональные возможности fs:

const fs = require('fs');
const fsPromises = fs.promises;

async function loadMonoCounter() {
    const data = await fsPromises.readFile('monolitic.txt', 'binary');
    return new Buffer(data);
}

Импорт fs и fs.promises отдельно даст доступ ко всей fs API, при этом сохраняя его более читабельным... Так что что-то вроде следующего примера легко выполнить.

// the 'next example'
fsPromises.access('monolitic.txt', fs.constants.R_OK | fs.constants.W_OK)
    .then(() => console.log('can access'))
    .catch(() => console.error('cannot access'));

E сть fs.readFileSync( path, options ) метод, который является синхронным.

      const fs = require("fs");
const util = require("util");
const readFile = util.promisify(fs.readFile);
const getContent = async () => {
let my_content;
try {
  const { toJSON } = await readFile("credentials.json");
  my_content = toJSON();
  console.log(my_content);
} catch (e) {
  console.log("Error loading client secret file:", e);
 }
};

Я читаю файл с помощью Promise. Для меня правильно:

      const fs = require('fs')

//function which return Promise
const read = (path, type) => new Promise((resolve, reject) => {
  fs.readFile(path, type, (err, file) => {
    if (err) reject(err)
    resolve(file)
  })
})

//example how call this function
read('file.txt', 'utf8')
    .then((file) => console.log('your file is '+file))
    .catch((err) => console.log('error reading file '+err))

//another example how call function inside async
async function func() {
  let file = await read('file.txt', 'utf8')
  console.log('your file is '+file)
}

Это создает строку из содержимого вашего файла, вам не нужно использовать обещания, чтобы это работало.

      const fs = require('fs');
const data = fs.readFileSync("./path/to/file.json", "binary");

Вы можете найти мой подход ниже: сначала мне потребовалась fs как fsBase, затем я поместил «обещания» в переменную fs.

      const fsBase = require('fs');
const fs = fsBase.promises

const fn = async () => {
    const data = await fs.readFile('example.txt', 'utf8');
    console.log(data);
};

fn();
Другие вопросы по тегам