Node.js'de dosya sistemini async / await ile kullanma


130

Bazı dosya sistemi işlemlerinde async / await kullanmak istiyorum. Normalde async / await iyi çalışıyor çünkü kullandığım için babel-plugin-syntax-async-functions.

Ancak bu kodla names, tanımsız olduğu if durumuyla karşılaşıyorum :

import fs from 'fs';

async function myF() {
  let names;
  try {
    names = await fs.readdir('path/to/dir');
  } catch (e) {
    console.log('e', e);
  }
  if (names === undefined) {
    console.log('undefined');
  } else {
    console.log('First Name', names[0]);
  }
}

myF();

Kodu geri arama cehennemi sürümünde yeniden oluşturduğumda her şey yolunda ve dosya adlarını alıyorum. İpuçlarınız için teşekkürler.

Yanıtlar:


140

8.0.0 düğümünden başlayarak, şunu kullanabilirsiniz:

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

const readdir = util.promisify(fs.readdir);

async function myF() {
  let names;
  try {
    names = await readdir('path/to/dir');
  } catch (err) {
    console.log(err);
  }
  if (names === undefined) {
    console.log('undefined');
  } else {
    console.log('First Name', names[0]);
  }
}

myF();

Bkz. Https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original


7
Düğüm v8.9.4'te bir SyntaxError: Unexpected token importhata mesajı aldım . node8, importbelirteci varsayılan olarak destekliyor mu?
makerj

9
@makerj yeni importsözdizimini kullanıyor . Şu anda bazı aktarım gerektiriyor. const fs = require('fs')Ya da kullanmakta sorun olmazconst { promisify } = require('util')
Josh Sandlin

2
Noob sorusu, ama {err, names} = functionsözdiziminin adı ne ?
Kasım

6
@Qasim buna yıkıcı görev denir.
jaredkwright

1
@AlexanderZeitler Bu doğru olabilir. Bunun gerçekten doğru bir yıkım kullanımı olup olmadığına bakmadım. Eşzamansız bekleme durumunda, bence sadece yaparsınız names = await readdir('path/to/dir');ve eğer blokta bir erridare varsa catch. Her iki durumda da sözdiziminin adı, sadece Kasım'ın sorusuna yanıt olarak verilen atamayı yıkıyor.
jaredkwright

88

Eşzamansız için yerel destek, Düğüm 11'den beri fs işlevlerini bekliyor

Node.JS 11.0.0 (kararlı) ve 10.0.0 (deneysel) sürümünden bu yana, önceden vaat edilmiş dosya sistemi yöntemlerine erişiminiz var ve bunları try catch , geri döndürülen değerinin içerip içermediğini kontrol etmek yerine istisna işleme bir hata.

API çok temiz ve zariftir! Basitçe nesnenin .promisesüyesini kullanın fs:

import fs from 'fs';
const fsPromises = fs.promises;

async function listDir() {
  try {
    return fsPromises.readdir('path/to/dir');
  } catch (err) {
    console.error('Error occured while reading directory!', err);
  }
}

listDir();

Bu API, Node.js sitesindeki Dosya Sistemi belgelerine göre 11.x sürümünden itibaren kararlıdır
TheHanna

1
@DanStarns Sözünüzü tutmazsanız return await, yakalama bloğunun bir faydası yok ... Zaten bazen dönmeden önce beklemek iyi bir uygulamadır
538ROMEO

@ 538ROMEO şimdi buna ve sağınıza baktı. Gösterdiğiniz için teşekkürler.
DanStarns

Bu alternatif yöntemler için belgeler: nodejs.org/api/fs.html#fs_fs_promises_api
Jeevan Takhar

87

Node.js 8.0.0

Yerel eşzamansız / bekleme

Promisify

Bu versiyonda, istediğiniz ülkedeki yerli node.js fonksiyonunu kullanabilirsiniz util kütüphanede.

const fs = require('fs')
const { promisify } = require('util')

const readFileAsync = promisify(fs.readFile)
const writeFileAsync = promisify(fs.writeFile)

const run = async () => {
  const res = await readFileAsync('./data.json')
  console.log(res)
}

run()

Söz Sarma

const fs = require('fs')

const readFile = (path, opts = 'utf8') =>
  new Promise((resolve, reject) => {
    fs.readFile(path, opts, (err, data) => {
      if (err) reject(err)
      else resolve(data)
    })
  })

const writeFile = (path, data, opts = 'utf8') =>
  new Promise((resolve, reject) => {
    fs.writeFile(path, data, opts, (err) => {
      if (err) reject(err)
      else resolve()
    })
  })

module.exports = {
  readFile,
  writeFile
}

...


// in some file, with imported functions above
// in async block
const run = async () => {
  const res = await readFile('./data.json')
  console.log(res)
}

run()

Tavsiye

try..catchÜst istisnai durumu yeniden atmak istemiyorsanız, her zaman bekleme blokları için kullanın .


Bu tuhaf. SyntaxError alıyorum: await yalnızca zaman uyumsuz işlevde geçerlidir ... öfkeyle ağlıyor.
Vedran Maricevic.

2
@VedranMaricevic. yorumlara bak, awaither zaman asyncblokta olmalı :)
dimpiax

@VedranMaricevic. Bunu const res = await readFile('data.json') console.log(res)bazı eşzamansız işlevlerde aramanız gerekir
Jayraj

söz sarmak fs.promisesve onu kullanmak benim async/awaitiçin çok kafa karıştırıcı
oldboy

@PrimitiveNom Promise then, catchvb. İçinde geleneksel şekilde kullanılabilir. Async / await nerede modern davranış akışıdır.
dimpiax

43

Dosya-API fs.readdirbir söz vermediği için yanlış davranış sergileyebilirsiniz . Sadece bir geri aranma alır. Eşzamansız-bekleme sözdizimi ile gitmek istiyorsanız, işlevi şu şekilde 'söz verebilirsiniz':

function readdirAsync(path) {
  return new Promise(function (resolve, reject) {
    fs.readdir(path, function (error, result) {
      if (error) {
        reject(error);
      } else {
        resolve(result);
      }
    });
  });
}

ve onun yerine arayın:

names = await readdirAsync('path/to/dir');

31

İtibariyle V10.0'da kullanabileceğinizfs.Promises

Kullanan örnek readdir

const { promises: fs } = require("fs");

async function myF() {
    let names;
    try {
        names = await fs.readdir("path/to/dir");
    } catch (e) {
        console.log("e", e);
    }
    if (names === undefined) {
        console.log("undefined");
    } else {
        console.log("First Name", names[0]);
    }
}

myF();

Kullanan örnek readFile

const { promises: fs } = require("fs");

async function getContent(filePath, encoding = "utf-8") {
    if (!filePath) {
        throw new Error("filePath required");
    }

    return fs.readFile(filePath, { encoding });
}

(async () => {
    const content = await getContent("./package.json");

    console.log(content);
})();

Harika çalışıyor, ancak ExperimentalWarning: The fs.promises API is experimentaluyarı ile ilgili açık soruna dikkat etmek önemlidir : github.com/pnpm/pnpm/issues/1178
DavidP

1
@DavidP hangi düğüm sürümünü kullanıyorsunuz? 12 ve üstü iyi çalışıyor
DanStarns

2
Evet! Kesinlikle doğru - Üzerinde bulunduğum sürümü belirtmeyi ihmal ettim: v10.15.3- mesajı bastırmak mümkündür. Ancak konu hala açık olduğundan bahsetmeye değer olduğunu düşündüm.
DavidP

1
@DavidP Demek istediğim bahsetmeye değer, beni yanlış anlamayın, ancak düğüm 12 şimdi LTS'de, bu yüzden Biggie değil.
DanStarns

Bunu tam olarak nasıl kullanıyorsun, mesela readFile? Bu vaatler konusunda yeniyim ve tek yapmak istediğim, getContentsenaryomun çeşitli bölümlerinde arayabileceğim ve bekleyebileceğim bir işleve sahip olmak , ancak bu çok kafa karıştırıcı
ihtiyar çocuk

8

Bu, sorunun TypeScript sürümüdür. Düğüm 11.0'dan sonra kullanılabilir:

import { promises as fs } from 'fs';

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

5

İşte benim için işe yarayan şey:

const fsp = require('fs-promise');

(async () => {
  try {
    const names = await fsp.readdir('path/to/dir');
    console.log(names[0]);
  } catch (e) {
    console.log('error: ', e);
  }
})();

Bu kod babel olmadan düğüm 7.6 çalışır uyum bayrak etkindir: node --harmony my-script.js. 7.7 düğümünden başlayarak, bu bayrağa bile ihtiyacınız yok !

Başlangıçta fspyer alan kütüphane, fs(ve fs-ext) için vaat edilmiş bir sarmalayıcıdır .

Bu günlerde babel olmadan düğümde neler yapabileceğiniz konusunda gerçekten çok heyecanlıyım! Yerli async/ awaitkod yazmayı böyle bir zevk haline getirin!

GÜNCELLEME 2017-06: fs-promise modülü kullanımdan kaldırıldı. fs-extraBunun yerine aynı API ile kullanın .


Bunun için bir kitaplık indirmek tamamen aşırılıktır, bağımlılık şişkinliği, topluluğun şiddetle karşı çıkması gereken bir şeydir, sadece 0 bağımlılığı olan lib'leri olan yeni bir npmj'lerin ortaya çıkması gerekir
PirateApp

5

Özel işlevlere kıyasla https://github.com/davetemplin/async-file gibi bir npm paketi kullanmanızı öneririz . Örneğin:

import * as fs from 'async-file';

await fs.rename('/tmp/hello', '/tmp/world');
await fs.appendFile('message.txt', 'data to append');
await fs.access('/etc/passd', fs.constants.R_OK | fs.constants.W_OK);

var stats = await fs.stat('/tmp/hello', '/tmp/world');

Diğer cevaplar güncel değil


5

Ben ihracat bu modülü yardım bu az şey var promisified sürümlerini fsfonksiyonları

const fs = require("fs");
const {promisify} = require("util")

module.exports = {
  readdir: promisify(fs.readdir),
  readFile: promisify(fs.readFile),
  writeFile: promisify(fs.writeFile)
  // etc...
};

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.