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

תומאס סטיינר
תומאס סטיינר

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

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

מה חדש?

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

  • truncate(newSize): משנה את הגודל של הקובץ המשויך לנקודת האחיזה של הגישה, כך שהוא יהיה באורך של newSize בייטים. אם newSize גדול מהגודל הנוכחי של הקובץ, הוא ימלא את הקובץ ב-null בייטים, אחרת הוא יקצר את הקובץ.
  • getSize(): מחזירה את גודל הקובץ המשויך לנקודת האחיזה של הגישה בבייטים.
  • flush(): מוודאת שתוכן הקובץ המשויך למזהה הגישה מכיל את כל השינויים שבוצעו דרך write().
  • close(): מסיר את נקודת האחיזה של הגישה ולאחר מכן סוגר אותה. סגירה של נקודת גישה משביתה את כל הפעולות הנוספות בה ומשחררת את הנעילה ברשומה שמשויכת אליה.
// 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 */