Wie lese ich eine Datei mit async / warte richtig?


119

Ich kann nicht herausfinden, wie async/ awaitfunktioniert. Ich verstehe es leicht, aber ich kann es nicht zum Laufen bringen.

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

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

Ich weiß, dass ich es gebrauchen könnte readFileSync, aber wenn ich es tue, weiß ich, dass ich es nie verstehen werde async/ awaitund ich werde das Problem einfach begraben.

Ziel: Rufen Sie loadMonoCounter()den Inhalt einer Datei auf und geben Sie ihn zurück.

Diese Datei wird bei jedem incrementMonoCounter()Aufruf (bei jedem Laden der Seite) inkrementiert . Die Datei enthält den Speicherauszug eines Puffers in Binärform und wird auf einer SSD gespeichert.

Egal was ich mache, ich bekomme eine Fehlermeldung oder undefinedin der Konsole.


Antworten:


165

Um await/ zu verwenden async, benötigen Sie Methoden, die Versprechen zurückgeben. Die Kern-API-Funktionen tun dies nicht ohne Wrapper wie 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);
})

Hinweis: readFileSyncNimmt keinen Rückruf entgegen, gibt die Daten zurück oder löst eine Ausnahme aus. Sie erhalten nicht den gewünschten Wert, da die von Ihnen bereitgestellte Funktion ignoriert wird und Sie den tatsächlichen Rückgabewert nicht erfassen.


3
Vielen Dank, ich wusste nicht, dass ich die Kern-API umschließen muss. Du bist toll.
Jeremy Dicaire

4
Die Kern-API datiert vor der modernen Promise-Spezifikation und der Übernahme von async/ await, daher ist dies ein notwendiger Schritt. Die gute Nachricht ist promisifynormalerweise, dass es ohne Probleme funktioniert.
Tadman

1
Dies behandelt das Chaos, dass Async-Wait mit FS nicht normal genutzt werden kann. Danke dafür! Du hast mir eine Menge gespart! Es gibt keine Antwort, die dies wirklich so anspricht wie Ihre.
Jacobhobson

3
Auch das Warten ist irgendwie überflüssig, da es abgeleitet werden kann. Nur wenn Sie in einem Beispiel explizit warten möchten, können Sie dies tun const file = await readFile...; return file;.
Bigkahunaburger

1
@shijin Bis die Node-Core-API auf Versprechen umschaltet, was zu diesem Zeitpunkt unwahrscheinlich ist, dann ja. Es gibt jedoch NPM-Wrapper, die dies für Sie tun.
Tadman

146

Seit Node v11.0.0 sind fs-Versprechen nativ verfügbar ohne promisify:

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

4
Keine zusätzlichen Bibliotheken, sauber und einfach - dies sollte vorzuziehen sein
Adam Bubela

2
Ab dem 21. Oktober 2019 ist v12 eine aktive LTS-Version
cbronson

16
import { promises as fs } from "fs";Wenn Sie die Importsyntax verwenden möchten.
tr3online

21

Dies ist die TypeScript-Version von @ Joels Antwort. Es kann nach Knoten 11.0 verwendet werden:

import { promises as fs } from 'fs';

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

18

Sie können den Befehl readFile einfach mit einem Versprechen wie folgt umschließen:

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

dann benutze:

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

Wird das Warten nicht in der asynchronen Funktion verwendet?
VikasBhat

@VikasBhat Ja, die Wartezeile oben wird in einer anderen asynchronen Funktion verwendet, wie es die Spezifikation erfordert.
Whoshotdk

8

Sie können fs.promisesverfügbar nativ seit Node v11.0.0 verwenden

import fs from 'fs';

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

Wenn Sie nur Versprechen verwenden möchten, können Sie so etwas wieconst fs = require('fs').promises
Nathanfranke

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.