שינוי תוכנה שעלול לגרום לכשל: שיטות סנכרון של AccessHandles

מערכת הקבצים הפרטית של המקור מספקת גישה לסוג מיוחד של קובץ שעבר אופטימיזציה רבה לביצועים. לדוגמה, היא מספקת גישת כתיבה בלעדית במקום לתוכן של קובץ. מפתחים יכולים לקבל גישה לקבצים כאלה על ידי קריאה ל-createSyncAccessHandle(), שיטה שחשופה באובייקטים מסוג FileSystemFileHandle. הקריאה הזו יוצרת FileSystemSyncAccessHandle.

FileSystemSyncAccessHandle הוא פרימיטיב של קובץ שמספק גישה יעילה לקבצים מקומיים. אחד מהתרחישים העיקריים לשימוש בו הוא אפליקציות שמעבירות קוד C/C++ ל-Wasm. עם זאת, עדיין אין תמיכה מלאה בקריאות אסינכרוניות ב-Wasm, והשימוש בספרייה Asyncify כחלופה גורם לירידה משמעותית בביצועים. הפיכת כל השיטות של FileSystemSyncAccessHandle לסינכרוניות תואמת לציפיות של אפליקציות מבוססות-Wasm מ-API קובץ סינכרוני דמוי POSIX. כך ה-API הופך לארגונומי יותר ומניב שיפור משמעותי בביצועים.

מה חדש?

FileSystemSyncAccessHandle חושף את השיטות הבאות, שהיו בעבר אסינכרוניות, אבל הן סינכרוניות החל מגרסה 108 של Chromium.

  • truncate(newSize): שינוי הגודל של הקובץ המשויך למפתח הגישה כך שיהיה באורך newSize בייטים. אם newSize גדול מגודל הקובץ הנוכחי, הקובץ יאוכלס בבייטים ריקים. אחרת, הקובץ יקוצר.
  • getSize(): הפונקציה מחזירה את גודל הקובץ המשויך למפתח הגישה, בבייט.
  • flush(): מוודא שתוכן הקובץ שמשויך למפתח הגישה מכיל את כל השינויים שבוצעו דרך write().
  • close(): מנקה את ה-handle של הגישה ואז סוגר אותו. סגירת הרשאת הגישה משביתה פעולות נוספות עליה ומבטלת את הנעילה של הרשומה שמשויכת להרשאת הגישה.
// In a `Worker`:
const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle('test', { create: true });
// `createSyncAccessHandle()` is still async.
const accessHandle = await fileHandle.createSyncAccessHandle();
// Both `read()` and `write()` were sync before.
accessHandle.read(/* ... */);
accessHandle.write(/* ... */);

// New: synchronous as of Chromium 108.
console.log(accessHandle.getSize());
accessHandle.truncate(123);
accessHandle.flush();
accessHandle.close();

מה עליי לעשות?

חשוב לזכור ששינוי שיטות מאסינכרוניות לסינכררוניות הוא שינוי שחשוף לאינטרנט שעלול לגרום לשיבושים. השימוש ב-await בשיטות סינכרוניות הוא פעולה ללא תוצאה, אבל כל שימוש ב-Promise.then() יגרום לשגיאה. אם שרשרתם קריאה ל-then() על התוצאה של אחת מהשיטות שהיו אסינכרוניות בעבר ועכשיו הן סינכרוניות, תצטרכו לשנות את הקוד.

// (✅) This won't break, but you better remove the superfluous `await`:
await accessHandle.flush();
// ✅ Correct:
accessHandle.flush();
// ⛔️ This will break, and you need to restructure your code:
accessHandle.flush().then(/* Follow-up code */);
// ✅ Correct:
accessHandle.flush();
/* Follow-up code */