fs/promises היא הגרסה של המודול fs של Node שמבוססת על promises. הפונקציות שלה (readFile, writeFile, readdir, stat, mkdir, rm, rename וכל השאר) מחזירות promise במקום לקבל callback, כך שעושים להן await ותופסים שגיאות עם try/catch. ייבאו אותה עם require('fs/promises') או import fs from 'fs/promises'.
הוא מדפיס [ 'write docs', 'ship it' ]: כל await מחכה לפעולה אחת לפני שהשורה הבאה רצה, כך שההוספה תמיד קורית אחרי הכתיבה הראשונה. ב-ES module, await עובד ברמה העליונה; ב-CommonJS, עטפו את הקוד בפונקציה async.
הפונקציות שתשתמשו בהן הכי הרבה
השמות זהים ל-API של ה-callbacks, רק בלי ה-callback. הדפים על readFile ועל writeFile מכסים את שתיהן בפירוט.
| פונקציה | מה היא עושה | מה ה-promise מחזיר |
|---|---|---|
readFile(path, 'utf8') | קוראת קובץ שלם | את התוכן |
writeFile(path, data) | יוצרת או מחליפה קובץ | undefined |
appendFile(path, data) | מוסיפה לסוף | undefined |
readdir(path) | מציגה את תוכן התיקייה | מערך של שמות |
stat(path) | גודל, תאריכים, קובץ או תיקייה | אובייקט Stats |
mkdir(path, { recursive: true }) | יוצרת תיקיות | את התיקייה הראשונה שנוצרה, או undefined |
rename(from, to) | מעבירה או משנה שם | undefined |
rm(path, { recursive: true, force: true }) | מוחקת קובץ או תיקייה | undefined |
רשימת תיקייה עם readdir ו-stat
readdir מחזיר שמות בלבד. קראו ל-stat על כל אחד כדי לקבל את הגודל שלו או להבדיל בין קבצים לתיקיות, או העבירו { withFileTypes: true } כדי לקבל רשומות שכבר יודעות מה הסוג שלהן.
הלולאה מדפיסה README.md 6 bytes, notes.txt 3 bytes ו-src folder. stat נדחה עם ENOENT עבור נתיב שלא קיים, וזה הופך אותו לבדיקת קיום מהירה כשאתם רוצים גם את הפרטים.
שינוי שם, העברה ומחיקה
rename גם משנה שם וגם מעביר קובץ (באותו כונן). rm מוחק; הוא צריך recursive: true בשביל תיקייה שיש בה תוכן, ו-force: true כדי לא להיכשל כשהנתיב כבר לא קיים.
הקובץ עובר מ-drafts ל-published בשמו החדש, ואחרי rm התיקייה blog מכילה רק את published. הסירו את force: true מה-rm השני והוא יידחה עם ENOENT.
טיפול בשגיאות עם try/catch
פעולה שנכשלת דוחה את ה-promise שלה. עם await, הדחייה הזו הופכת לחריגה שתופסים כמו כל חריגה אחרת. ה-code של השגיאה אומר מה השתבש.
הקריאה הראשונה לא מוצאת קובץ ומחזירה []; השנייה מדפיסה Ada. קודים שכדאי להכיר: ENOENT (אין קובץ כזה), EEXIST (כבר קיים), EISDIR (תיקייה במקום שבו ציפו לקובץ), ENOTEMPTY (בתיקייה עדיין יש תוכן) ו-EACCES (אין הרשאה).
promise שלא עושים לו await ולא .catch() הופך ל-unhandled rejection כשהוא נכשל, ו-Node יוצא עם שגיאה. עשו await לכל קריאה, או החזירו את ה-promise שלה לקוד קורא שעושה זאת.
קריאה של כמה קבצים בבת אחת עם Promise.all
לולאת for עם await קוראת קבצים אחד אחרי השני. כשהקריאות לא תלויות זו בזו, התחילו את כולן וחכו פעם אחת עם Promise.all: הדיסק עובד עליהן באותו זמן.
Promise.all שומר על הסדר של מערך הקלט, כך שהתוצאה היא [ 'alpha', 'beta', 'gamma' ] לא משנה איזו קריאה הסתיימה ראשונה, והאורך המחובר הוא 14. שנו את 'b.txt' במערך ל-'x.txt', וכל ה-await יידחה עם ENOENT.
אם אתם צריכים כל תוצאה גם כשחלק מהקריאות נכשלות, השתמשו ב-Promise.allSettled; הדף על promises מכסה את שתיהן.
טעויות נפוצות
לבלבל בין שני המודולים. require('fs').readFile רוצה callback; require('fs/promises').readFile מחזיר promise. קריאה לגרסת ה-callback בלי callback זורקת The "cb" argument must be of type function.
לשכוח await. const text = fs.readFile(...) הוא promise שעוד ממתין, ו-text.split זורק text.split is not a function.
כתיבות במקביל לקובץ אחד. Promise.all עם כמה כתיבות לאותו נתיב יכול להשאיר תוכן מעורבב. הריצו אותן אחת אחרי השנייה.
שאלות נפוצות
מה ההבדל בין fs.promises ל-fs/promises?
אין הבדל. require('fs').promises ו-require('fs/promises') הם אותו אובייקט. הנתיב fs/promises (או node:fs/promises) הוא הדרך המקובלת לייבא אותו היום.
יש existsSync ב-fs/promises?
לא. ב-API של ה-promises יש access, שנדחה כשהנתיב חסר, אבל הדפוס המקובל הוא לקרוא לפעולה שאתם צריכים ולתפוס ENOENT. existsSync מהמודול fs הרגיל עדיין עובד לבדיקות מהירות.
האם fs/promises איטי יותר מה-API של ה-callbacks?
מעט, בגלל התקורה של ה-promises, אבל זה זניח לעומת זמן הדיסק. בחרו לפי קריאוּת; ה-API של ה-promises הוא זה שרוב הקוד החדש משתמש בו.
איך הופכים פונקציית fs עם callback ל-promise?
כמעט אף פעם לא צריך, כי fs/promises מכסה את פונקציות הקבצים. ל-APIs אחרים עם callbacks, util.promisify(fn) מחזיר גרסה שמחזירה promise.