جاوااسکریپت - استفاده از سیستم فایل در Node.js با async/await
من میخواهم از async/await با برخی عملیات سیستم فایل استفاده کنم. به طور معمول async/await به خوبی کار میکند زیرا من از babel-plugin-syntax-async-functions استفاده میکنم.
اما با این کد، به حالتی از if برخورد میکنم که 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();
وقتی کد را به نسخه جهنم کالبک بازسازی میکنم همه چیز خوب است و نام فایلها را دریافت میکنم. از راهنماییهای شما ممنونم.
پاسخ شماره ۱
پشتیبانی بومی از توابع fs با async/await از زمان Node 11
از Node.js نسخه 11.0.0 (پایدار) و 10.0.0 (آزمایشی)، میتوانید به روشهای سیستم فایل که از قبل به پرامیس تبدیل شدهاند دسترسی داشته باشید. به لطف پرامیسها میتوانید به سادگی از try catch برای مدیریت استثناها استفاده کنید به جای اینکه بررسی کنید آیا مقدار بازگشتی callback شامل خطا است یا نه.
رابط برنامهنویسی (API) بسیار تمیز و شیک است! به سادگی متدهای سیستم فایل را از fs/promises وارد کنید به جای اینکه مستقیماً از fs وارد کنید:
import fs from 'fs/promises'
async function listDir() {
try {
return await fs.readdir('path/to/dir')
} catch (err) {
console.error('Error occurred while reading directory:', err)
}
}
listDir()
پاسخ شماره ۲
ابتدا با نسخهٔ ۸.۰.۰ نود، شما میتوانید از این استفاده کنید:
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
پاسخ شماره ۳
Node.js 8.0.0
آسنکرون بومی/انتظار
به وعدهای تبدیل کردن
از این نسخه، شما میتوانید از تابع بومی Node.js از کتابخانه util استفاده کنید.
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 برای بلوکهای await استفاده کنید، اگر نمیخواهید استثنا را به بالاتر دوباره پرتاب کنید.
پاسخ شماره ۴
از نسخه 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);
})();
پاسخ شماره ۵
ممکن است رفتار نادرستی ایجاد کنید زیرا File-Api fs.readdir یک پرامیس برنمیگرداند. این تنها یک کالبک میگیرد. اگر میخواهید از سینتکس 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');
پاسخ شماره ۶
نسخه Node v14.0.0 و بالاتر
شما میتوانید فقط این کار را انجام دهید:
import { readdir } from "fs/promises";
دقیقاً مانند روشی که از "fs" ایمپورت میکنید
برای جزئیات بیشتر این PR را ببینید: https://github.com/nodejs/node/pull/31553
پاسخ شماره ۷
این نسخه 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);
}
