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

מערכת הקבצים הפרטית של המקור מספקת גישה לסוג מיוחד של קובץ שעבר אופטימיזציה רבה לביצועים. לדוגמה, היא מספקת גישת כתיבה במקום (in-place) וגישת כתיבה בלעדית לתוכן של הקובץ. מפתחים יכולים לקבל גישה לקבצים כאלה על ידי קריאה ל-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 */