Como ler o arquivo com async / await corretamente?


120

Não consigo descobrir como async/ awaitfunciona. Eu entendo um pouco, mas não consigo fazer funcionar.

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

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

Sei que poderia usar readFileSync, mas se usar , sei que nunca vou entender async/ awaite vou simplesmente enterrar o problema.

Objetivo: Ligar loadMonoCounter()e retornar o conteúdo de um arquivo.

Esse arquivo é incrementado toda vez que incrementMonoCounter()é chamado (a cada carregamento de página). O arquivo contém o dump de um buffer em binário e é armazenado em um SSD.

Não importa o que eu faça, recebo um erro undefinedno console.


Respostas:


165

Para usar await/ asyncvocê precisa de métodos que retornam promessas. As funções principais da API não fazem isso sem wrappers como promisify:

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

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

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

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

Como uma observação, readFileSyncnão recebe um retorno de chamada, ele retorna os dados ou lança uma exceção. Você não está obtendo o valor desejado porque a função fornecida é ignorada e você não está capturando o valor de retorno real.


3
Obrigado, eu não sabia que precisava envolver a API principal. Você é demais.
Jeremy Dicaire

4
A API principal é anterior à especificação moderna da Promise e à adoção de async/ await, portanto, essa é uma etapa necessária. A boa notícia é que promisifygeralmente funciona sem problemas.
tadman

1
Isso lida com a bagunça de não ser capaz de aproveitar async-await com FS normalmente. Obrigado por isso! Você me salvou uma tonelada! Não há resposta que realmente trate disso como a sua.
jacobhobson

3
Também await é meio redundante, pois pode ser inferido. Somente se você quiser explicitamente esperar no exemplo, você pode fazer const file = await readFile...; return file;.
bigkahunaburger

1
@shijin Até que a API principal do Node mude para promessas, o que é improvável neste momento, então sim. No entanto, existem wrappers NPM que fazem isso por você.
tadman

149

Desde Node v11.0.0 fs promessas estão disponíveis nativamente sem promisify:

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

4
sem libs adicionais, limpo e simples - esta deve ser a resposta preferível
Adam Bubela 09/07/19

2
Desde 21 de outubro de 2019, a v12 é uma versão LTS ativa
cbronson

16
import { promises as fs } from "fs";se você quiser usar a sintaxe de importação.
tr3online

21

Esta é a versão TypeScript da resposta de @Joel. É utilizável após o Nó 11.0:

import { promises as fs } from 'fs';

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

18

Você pode facilmente envolver o comando readFile com uma promessa como esta:

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

então use:

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

O await não é usado na função assíncrona?
VikasBhat

@VikasBhat Sim, a linha de espera acima seria usada dentro de outra função assíncrona, pois a especificação exige que seja assim.
whoshotdk

8

Você pode usar o fs.promisesdisponível nativamente desde o 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)
  }
}

Se você só quiser usar promessas, pode fazer algo comoconst fs = require('fs').promises
nathanfranke

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.