async / await로 node.js에서 파일 시스템 사용


129

일부 파일 시스템 작업에 async / await를 사용하고 싶습니다. 일반적으로 async / await는 babel-plugin-syntax-async-functions.

그러나이 코드를 사용하면 names정의되지 않은 경우 가 발생합니다.

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();

코드를 콜백 지옥 버전으로 다시 빌드하면 모든 것이 정상이며 파일 이름을 얻습니다. 힌트 주셔서 감사합니다.

답변:


139

노드 8.0.0부터 다음을 사용할 수 있습니다.

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();

참조 https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original를


7
노드 v8.9.4에서 SyntaxError: Unexpected token import오류 메시지가 나타납니다. node8은 import기본적으로 토큰을 지원 합니까?
makerj

9
@makerj 그는 새로운 import구문을 사용하고 있습니다. 현재 일부 트랜스 파일이 필요합니다. 괜찮을 것 또한 사용 const fs = require('fs')또는const { promisify } = require('util')
조쉬 Sandlin 보낸

2
멍청한 질문이지만 {err, names} = function구문은 무엇입니까?
Qasim

6
@Qasim을 구조화 할당이라고합니다.
jaredkwright

1
@AlexanderZeitler 사실 일 수 있습니다. 나는 그것이 실제로 destructuring의 올바른 사용인지 확인하지 않았습니다. 비동기의 경우에는 기다리고 난 그냥 할 것이라고 생각 names = await readdir('path/to/dir');하고있는 경우 err에서 핸들이 catch블록. 어느 쪽이든 구문의 이름은 Qasim의 질문에 대한 응답으로 할당 된 비 구조화입니다.
jaredkwright

88

노드 11 이후 비동기 await fs 함수에 대한 기본 지원

Node.JS 11.0.0 (안정적) 및 버전 10.0.0 (실험적) 이후로 이미 약속 된 파일 시스템 메서드에 액세스 할 수 try catch있으며 콜백의 반환 값에 다음이 포함되어 있는지 확인하는 대신 예외 처리 와 함께 사용할 수 있습니다. 오류.

API는 매우 깨끗하고 우아합니다! 단순히 개체의 .promises구성원을 사용하십시오 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();

이 API는 Node.js 사이트 의 파일 시스템 문서 에 따라 버전 11.x부터 안정적입니다
TheHanna

1
@DanStarns 당신이 return await약속 하지 않으면 캐치 블록은 쓸모가 없습니다 ... 나는 씬즈가 돌아 오기 전에 기다리는 것이 좋은 습관입니다
538ROMEO

@ 538ROMEO는 방금 이것과 당신의 권리를 조사했습니다. 지적 해 주셔서 감사합니다.
DanStarns

이러한 대체 방법에 대한 문서 : nodejs.org/api/fs.html#fs_fs_promises_api
Jeevan Takhar

87

Node.js 8.0.0

네이티브 비동기 / 대기

약속하다

이 버전에서는 util 라이브러리의 기본 Node.js 함수를 사용할 수 있습니다 .

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()

약속 포장

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()

조언

try..catch예외를 다시 발생시키지 않으려면 항상 대기 블록에 사용하십시오 .


이건 이상해. SyntaxError : await is only valid in async function ... crying in rage.
Vedran Maricevic.

2
트윗 담아 가기 , 의견을보실 수 await항상 있어야합니다 async:) 블록
dimpiax

트윗 담아 가기 const res = await readFile('data.json') console.log(res)비동기 함수에서 호출해야 합니다
Jayraj

포장을 약속 fs.promises하고 그것을 사용 async/await그래서 나에게 혼란
올드 보이

@PrimitiveNom 약속은 내 전통적인 방법으로 사용할 수 있습니다 then, catch등 어디 비동기 / await를 현대적인 행동 흐름이다.
dimpiax

43

File-Api fs.readdir가 promise를 반환하지 않기 때문에 잘못된 동작을 생성 할 수 있습니다 . 콜백 만받습니다. async-await 구문을 사용하려면 다음과 같이 함수를 '약속'할 수 있습니다.

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

대신 호출하십시오.

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

31

현재 V10.0 , 당신은 사용할 수 있습니다fs.Promises

사용 예 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();

사용 예 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);
})();

훌륭하게 작동하지만 ExperimentalWarning: The fs.promises API is experimental경고 와 관련된 미해결 문제에 유의하는 것이 중요합니다 . github.com/pnpm/pnpm/issues/1178
DavidP

1
@DavidP 어떤 버전의 노드를 사용하고 있습니까? 12 이상은 잘 작동합니다
DanStarns

2
예! 절대적으로 맞습니다-현재 버전을 표시하는 것을 무시했습니다 v10.15.3.-메시지를 숨길 수 있습니다. 그러나 여전히 문제가 열려 있으므로 언급 할 가치가 있다고 생각했습니다.
DavidP

1
@DavidP 내 말은 언급할만한 가치가 있다는 뜻입니다. 오해하지 마세요.하지만 노드 12는 이제 LTS에 있으므로 Biggie가 아닙니다.
DanStarns

이걸 정확히 어떻게 사용 readFile합니까? 이 모든 약속에 대한 새로운 메신저입니다. 제가하고 싶은 것은 getContent스크립트 전체에 걸쳐 다양한 부분에서 호출하고 기다릴 수 있는 함수 를 갖는 것 입니다.하지만 이것은 매우 혼란 스럽습니다
oldboy

8

이것은 질문에 대한 TypeScript 버전입니다. Node 11.0 이후에 사용할 수 있습니다.

import { promises as fs } from 'fs';

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

5

나를 위해 일한 것은 다음과 같습니다.

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);
  }
})();

이 코드는 조화 플래그 가 활성화 된 경우 바벨없이 노드 7.6에서 작동합니다 : node --harmony my-script.js. 그리고 노드 7.7부터는 이 플래그가 필요하지 않습니다 !

fsp시작에 포함 된 라이브러리를위한 단지 promisified 래퍼 fs(과 fs-ext).

요즘 바벨없이 노드에서 할 수있는 일에 대해 정말 끝내 줬어요! 네이티브 async/ await코드 작성을 즐겁게 만드십시오!

업데이트 2017-06 : fs-promise 모듈은 더 이상 사용되지 않습니다. fs-extra대신 동일한 API와 함께 사용하십시오 .


이것에 대한 라이브러리를 다운로드하는 것은 순수 잔인한, 종속 팽만감은 지역 사회가 새로운 npmjs은 0 종속성 libs가 가지고 만들기로 와야한다 가리키고, 강력하게 반대해야한다는 무언가이다
PirateApp

5

사용자 지정 함수와 비교하여 https://github.com/davetemplin/async-file 과 같은 npm 패키지 사용을 권장 합니다. 예를 들면 :

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');

다른 답변은 오래되었습니다.


5

약속 된 버전의 fs함수 를 내보내는이 작은 도움말 모듈이 있습니다.

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

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.