Come leggere correttamente il file con async / await?


120

Non riesco a capire come async/ awaitfunziona. Lo capisco leggermente ma non riesco a farlo funzionare.

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

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

So che potrei usare readFileSync, ma se lo faccio, so che non capirò mai async/ awaite seppellirò il problema.

Obiettivo: chiamare loadMonoCounter()e restituire il contenuto di un file.

Quel file viene incrementato ogni volta che incrementMonoCounter()viene chiamato (ogni caricamento della pagina). Il file contiene il dump di un buffer in binario ed è memorizzato su un SSD.

Qualunque cosa faccia, ricevo un errore o undefinednella console.


Risposte:


165

Per usare await/ asynchai bisogno di metodi che restituiscano promesse. Le funzioni API principali non lo fanno senza wrapper come 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);
})

Come nota, readFileSyncnon accetta una richiamata, restituisce i dati o genera un'eccezione. Non ottieni il valore che desideri perché la funzione che fornisci viene ignorata e non stai acquisendo il valore di ritorno effettivo.


3
Grazie, non sapevo di aver bisogno di avvolgere l'API principale. Sei fantastico.
Jeremy Dicaire

4
L'API principale è precedente alla specifica moderna Promise e all'adozione di async/ await, quindi questo è un passaggio necessario. La buona notizia è che di promisifysolito funziona senza problemi.
tadman

1
Questo gestisce il pasticcio di non essere in grado di sfruttare normalmente l'attesa asincrona con FS. Grazie per questo! Mi hai salvato un sacco! Non c'è risposta che affronti davvero questo come la tua.
jacobhobson

3
Anche wait è un po 'ridondante poiché può essere dedotto. Solo se vuoi esplicitamente avere wait in esempio, puoi farlo const file = await readFile...; return file;.
bigkahunaburger

1
@shijin Fino a quando l'API principale del nodo non passa alle promesse, cosa improbabile a questo punto, allora sì. Tuttavia, esistono wrapper NPM che lo fanno per te.
tadman

150

Poiché le promesse fs di Node v11.0.0 sono disponibili in modo nativo senza promisify:

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

4
nessuna libreria aggiuntiva, pulita e semplice - questa dovrebbe essere una risposta preferibile
Adam Bubela

2
A partire dal 21 ottobre 2019, la v12 è una versione LTS attiva
cbronson

16
import { promises as fs } from "fs";se vuoi usare la sintassi di importazione.
tr3online

21

Questa è la versione TypeScript della risposta di @ Joel. È utilizzabile dopo il nodo 11.0:

import { promises as fs } from 'fs';

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

18

Puoi facilmente racchiudere il comando readFile con una promessa in questo modo:

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

quindi usa:

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

Attendere non è utilizzato all'interno della funzione asincrona?
VikasBhat

@VikasBhat Sì, la riga di attesa sopra verrà utilizzata all'interno di un'altra funzione asincrona poiché le specifiche richiedono che sia così.
whoshotdk

8

È possibile utilizzare fs.promisesdisponibile in modo nativo a partire da 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 vuoi usare solo le promesse, potresti fare qualcosa del tipoconst fs = require('fs').promises
nathanfranke il

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.