Làm thế nào để đọc tệp với async / await đúng cách?


120

Tôi không thể tìm ra cách thức async/ awaithoạt động. Tôi hơi hiểu nó nhưng tôi không thể làm cho nó hoạt động.

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

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

Tôi biết tôi có thể sử dụng readFileSync, nhưng nếu tôi làm vậy, tôi biết tôi sẽ không bao giờ hiểu async/ awaitvà tôi sẽ chôn vùi vấn đề.

Mục tiêu: Gọi loadMonoCounter()và trả về nội dung của một tệp.

Tệp đó được tăng lên mỗi khi incrementMonoCounter()được gọi (mỗi lần tải trang). Tệp chứa kết xuất của bộ đệm ở dạng nhị phân và được lưu trữ trên SSD.

Bất kể tôi làm gì, tôi đều gặp lỗi hoặc undefinedtrong bảng điều khiển.


Điều này có trả lời câu hỏi của bạn không? Sử dụng hệ thống tập tin trong Node.js với async / chờ đợi
KyleMit

Câu trả lời:


165

Để sử dụng await/ asyncbạn cần các phương thức trả về lời hứa. Các hàm API cốt lõi không làm điều đó nếu không có trình bao bọc như 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);
})

Như một lưu ý, readFileSynckhông thực hiện một cuộc gọi lại, nó trả về dữ liệu hoặc ném một ngoại lệ. Bạn không nhận được giá trị bạn muốn bởi vì chức năng bạn cung cấp bị bỏ qua và bạn không nắm bắt được giá trị trả về thực tế.


3
Cảm ơn, tôi không biết rằng tôi cần phải bọc API cốt lõi. Bạn thật tuyệt vời.
Jeremy Dicaire

4
API cốt lõi xác định trước thông số kỹ thuật Promise hiện đại và việc áp dụng async/ await, vì vậy đó là một bước cần thiết. Tin tốt là promisifythường làm cho nó hoạt động mà không có lộn xộn.
tadman

1
Điều này xử lý mớ hỗn độn của việc không thể tận dụng async-await với FS một cách bình thường. Cảm ơn vì điều này! Bạn đã tiết kiệm cho tôi một tấn! Không có câu trả lời nào thực sự giải quyết vấn đề này như của bạn.
jacobhobson

3
Ngoài ra, sự chờ đợi là hơi thừa vì nó có thể được suy luận. Chỉ nếu bạn muốn rõ ràng là có chờ đợi, bạn có thể làm const file = await readFile...; return file;.
bigkahunaburger

1
@shijin Cho đến khi API lõi Node chuyển sang hứa hẹn, điều này khó xảy ra vào thời điểm này, thì có. Tuy nhiên, có những trình bao bọc NPM làm điều đó cho bạn.
tadman

150

Vì các hứa hẹn Node v11.0.0 fs có sẵn mà không có promisify:

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

4
không libs bổ sung, sạch sẽ và đơn giản - thích hợp hơn câu trả lời này nên
Adam Bubela

2
Tính đến 21-Oct-2019, v12 là một LTS phiên bản hoạt động
cbronson

16
import { promises as fs } from "fs";nếu bạn muốn sử dụng cú pháp nhập.
tr3online ngày

21

Đây là phiên bản TypeScript của câu trả lời của @ Joel. Nó có thể sử dụng được sau Node 11.0:

import { promises as fs } from 'fs';

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

18

Bạn có thể dễ dàng bọc lệnh readFile với một lời hứa như sau:

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

sau đó sử dụng:

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

Không phải chờ đợi được sử dụng bên trong hàm không đồng bộ?
VikasBhat

@VikasBhat Có, dòng chờ đợi ở trên sẽ được sử dụng bên trong một hàm không đồng bộ khác vì thông số kỹ thuật yêu cầu nó phải như vậy.
whoshotdk

8

Bạn có thể sử dụng fs.promisesnguyên bản có sẵn kể từ 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)
  }
}

Nếu bạn chỉ muốn sử dụng những lời hứa, bạn có thể làm một cái gì đó giống nhưconst fs = require('fs').promises
nathanfranke

1

Có một fs.readFileSync( path, options )phương pháp, đó là đồng bộ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.