אחסון KV - המודול המובנה הראשון באינטרנט

ספקי דפדפנים ומומחים לביצועי אתרים אמרו מתחילת העשור האחרון שlocalStorage הוא איטי, ומפתחי אתרים צריכים להפסיק להשתמש בו.

למען ההוגנות, אלה שאומרים זאת לא טעות. localStorage הוא API סינכרוני שחוסם את ה-thread הראשי, ובכל פעם שנכנסים אליו עלולה למנוע מהדף להיות אינטראקטיבי.

הבעיה היא שה-API של localStorage פשוט כל כך מפתה, והחלופה האסינכרונית היחידה ל-localStorage היא IndexedDB, שלא ידוע לנו שהיא קלה לשימוש או לא תומכת ב-API.

כך המפתחים נשארים עם הבחירה בין משהו שקשה להשתמש בו לבין משהו רע לביצועים. ולמרות שיש ספריות שמציעות את הפשטות של API localStorage תוך שימוש בממשקי API אסינכרוניים לצורך אחסון, כולל אחת מהספריות האלה באפליקציה שלכם יש עלות של גודל קובץ, ואפשר לנצל אותה כחלק מתקציב הביצועים.

אבל מה אם אפשר היה לקבל את הביצועים של API לאחסון אסינכרוני בפשטות של ה-API של localStorage, בלי לשלם את עלות גודל הקובץ?

ובכן, יכול להיות שבקרוב. אנחנו עורכים ניסויים ב-Chrome עם פיצ'ר חדש שנקרא מודולים מובנים, והמוצר הראשון שאנחנו מתכננים לשלוח הוא מודול אחסון של מפתח/ערך אסינכרוני שנקרא KV Storage.

אבל לפני שנתחיל בפירוט של מודול האחסון של KV, אסביר למה הכוונה במודולים מובנים.

מהם מודולים מובנים?

מודולים מובנים דומים למודולים רגילים של JavaScript, אלא שלא צריך להוריד אותם כי הם נשלחים יחד עם הדפדפן.

בדומה לממשקי API מסורתיים לאינטרנט, גם המודולים המובנים צריכים לעבור תהליך של תקינה – לכל אחד מהם יהיה מפרט משלו שדורש בדיקת עיצוב וסימן תמיכה חיובי ממפתחי אתרים ומספקי דפדפנים אחרים לפני שתוכלו לשלוח אותו. (ב-Chrome, המודולים המובנים יפעלו לפי אותו תהליך השקה שבו אנחנו משתמשים כדי להטמיע ולשלוח את כל ממשקי ה-API החדשים).

בניגוד לממשקי API מסורתיים לאינטרנט, מודולים מובנים לא נחשפים בהיקף הגלובלי – הם זמינים רק באמצעות ייבוא.

אם לא חושפים מודולים מובנים באופן גלובלי, הם לא מוסיפים תקורה להפעלת הקשר חדש של סביבת זמן ריצה ב-JavaScript (למשל כרטיסייה חדשה, worker או Service Worker), והם לא צורכים זיכרון או מעבד (CPU) אלא אם הם יובאו בפועל. בנוסף, הם לא עלולים לגרום להתנגשויות בין שמות עם משתנים אחרים שמוגדרים בקוד.

כדי לייבא מודול מובנה, משתמשים בקידומת std: ואחריה מזהה המודול המובנה. לדוגמה, בדפדפנים נתמכים, אפשר לייבא את המודול של KV Storage עם הקוד הבא (ראו בהמשך איך להשתמש ב-Polyfill של KV Storage בדפדפנים לא נתמכים):

import storage, {StorageArea} from 'std:kv-storage';

מודול האחסון KV

המודול של KV Storage דומה בפשטות שלו ל-API של localStorage, אבל צורת ה-API שלו דומה יותר ל-JavaScript Map. במקום getItem(), setItem() ו-removeItem(), יש בו get(), set(), ו-delete(). יש לו גם שיטות אחרות דמויי-מפה שלא זמינות ל-localStorage, כמו keys(), values() ו-entries(), וכמו Map, המפתחות שלו לא חייבים להיות מחרוזות. הם יכולים להיות כל סוג שניתן להציג אותו באופן מדורג.

בניגוד ל-Map, כל השיטות של KV Storage מחזירות הבטחות או איטרטורים אסינכרוניים (מכיוון שהנקודה העיקרית של המודול הזה היא שלא סינכרוני, בניגוד ל-localStorage). לפרטים נוספים על ה-API המלא אפשר לעיין במפרט.

כפי שאולי שמתם לב מדוגמת הקוד שלמעלה, למודול של KV Storage יש ייצוא אחד שמוגדר כברירת מחדל storage וייצוא אחד בשם StorageArea.

storage הוא מופע של המחלקה StorageArea בשם 'default', וזה מה שהמפתחים ישתמשו בו הכי הרבה בקוד האפליקציה שלהם. המחלקה StorageArea ניתנת למקרים שבהם נדרש בידוד נוסף (למשל, ספריית צד שלישי שמאחסנת נתונים ורוצה למנוע התנגשויות עם נתונים שמאוחסנים במכונת ברירת המחדל storage). נתוני StorageArea מאוחסנים במסד נתונים של IndexedDB בשם kv-storage:${name}, כאשר השם הוא השם של המכונה StorageArea.

דוגמה לשימוש במודול KV Storage בקוד:

import storage from 'std:kv-storage';

const main = async () => {
  const oldPreferences = await storage.get('preferences');

  document.querySelector('form').addEventListener('submit', async () => {
    const newPreferences = Object.assign({}, oldPreferences, {
      // Updated preferences go here...
    });

    await storage.set('preferences', newPreferences);
  });
};

main();

מה קורה אם דפדפן לא תומך במודול מובנה?

אם אתם מכירים את השימוש במודולים של JavaScript מקוריים בדפדפנים, אתם בטח יודעים (לפחות עד עכשיו) שייבוא של כל תוכן מלבד כתובת URL יגרום לשגיאה. ו-std:kv-storage אינה כתובת URL חוקית.

נשאלת השאלה הבאה: האם אנחנו צריכים להמתין עד שכל הדפדפנים יתמכו במודולים מובנים לפני שנוכל להשתמש בהם בקוד שלנו? למרבה המזל, התשובה היא לא!

אפשר להשתמש במודולים מובנים ברגע שאפילו דפדפן אחד תומך בהם, בעזרת תכונה אחרת שאנחנו מתנסים איתה בשם ייבוא מפות.

ייבוא מפות

ייבוא מפות הוא בעצם מנגנון שמאפשר למפתחים להוסיף מזהי ייבוא למזהה חלופי אחד או יותר.

זו יכולת רבת-עוצמה כי היא מאפשרת לשנות (בזמן ריצה) את האופן שבו הדפדפן מטפל במזהה ייבוא מסוים בכל האפליקציה.

כשמדובר במודולים מובנים, אפשר להפנות ל-Polyfill של המודול בקוד האפליקציה, אבל דפדפן שתומך במודול המובנה יוכל לטעון את הגרסה הזו במקום זאת!

כך מצהירים על מפת ייבוא כדי שהפעולה הזו תפעל עם המודול של KV Storage:

<!-- The import map is inlined into your page -->
<script type="importmap">
{
  "imports": {
    "/path/to/kv-storage-polyfill.mjs": [
      "std:kv-storage",
      "/path/to/kv-storage-polyfill.mjs"
    ]
  }
}
</script>

<!-- Then any module scripts with import statements use the above map -->
<script type="module">
  import storage from '/path/to/kv-storage-polyfill.mjs';

  // Use `storage` ...
</script>

הנקודה העיקרית בקוד שלמעלה היא שכתובת ה-URL /path/to/kv-storage-polyfill.mjs ממופה לשני משאבים שונים: std:kv-storage ואז לכתובת ה-URL המקורית, /path/to/kv-storage-polyfill.mjs.

לכן, כשהדפדפן נתקל בהצהרת ייבוא שמפנה לכתובת האתר הזו (/path/to/kv-storage-polyfill.mjs), הוא מנסה קודם לטעון std:kv-storage, ואם הוא לא מצליח לטעון אותו, הוא חוזר לטעינה /path/to/kv-storage-polyfill.mjs.

שוב, הקסם הוא שהדפדפן לא צריך לתמוך בייבוא של מפות או במודולים מובנים כדי שהשיטה הזו תפעל, כי כתובת ה-URL שמועברת להצהרת הייבוא היא כתובת ה-URL של ה-polyfill. ה-Polyfill הוא לא חלופה, אלא ברירת המחדל. המודול המובנה לשיפור הדרגתי!

מה לגבי דפדפנים שלא תומכים בכלל במודולים?

כדי להשתמש במפות ייבוא כדי לטעון מודולים מובנים באופן מותנה, צריך להשתמש בפועל בהצהרות import, כלומר צריך להשתמש גם בסקריפטים של מודולים, כלומר <script type="module">.

נכון לעכשיו, יותר מ-80% מהדפדפנים תומכים במודולים, ובדפדפנים שלא תומכים במודול הזה, אפשר להשתמש בשיטה 'מודול' או 'nomodule' כדי להציג חבילה מדור קודם. שימו לב שכשיוצרים את ה-build של nomodule, צריך לכלול את כל ה-Polyfills כי אתם יודעים בוודאות שדפדפנים שלא תומכים במודולים לא יתמכו במודולים מובנים.

הדגמה של אחסון KV

כדי להמחיש את האפשרות להשתמש במודולים מובנים ועדיין לתמוך בדפדפנים ישנים יותר, יצרתי הדגמה שמשלבת את כל הטכניקות שתוארו למעלה, ופועלת בכל הדפדפנים היום:

  • דפדפנים שתומכים במודולים, בייבוא של מפות ובמודול המובנה לא טוענים קוד מיותר.
  • דפדפנים שתומכים במודולים ובייבוא מפות, אבל לא תומכים במודול המובנה, טוענים את ה-Polyfill של KV Storage (דרך טוען המודול של הדפדפן).
  • דפדפנים שתומכים במודולים, אבל לא תומכים במפות ייבוא, טוענים גם את ה-Polyfill של KV Storage (באמצעות טוען המודול של הדפדפן).
  • דפדפנים שלא תומכים בכלל במודולים מקבלים את ה-Polyfill של KV Storage בחבילה הקודמת שלהם (נטענת באמצעות <script nomodule>).

ההדגמה מתארחת ב-Glitch, כך שאפשר להציג את המקור שלה. יש לי גם הסבר מפורט על ההטמעה ב-README. אתם מוזמנים להציץ ולראות איך הוא בנוי.

כדי לראות בפועל את המודול המובנה המובנה, צריך לטעון את ההדגמה ב-Chrome 74 ואילך כשדגל התכונות הניסיוניות של פלטפורמת האינטרנט מופעל (chrome://flags/#enable-experimental-web-platform-features).

תוכלו לוודא שהמודול המובנה נטען כי לא תראו את הסקריפט של ה-Polyfill בחלונית המקור בכלי הפיתוח; במקום זאת, תוצג לכם גרסת המודול המובנית (עובדה כיפית: תוכלו לבדוק את קוד המקור של המודול או אפילו להוסיף בו נקודות עצירה!):

מקור המודול &#39;אחסון KV&#39; בכלי הפיתוח ל-Chrome

נשמח לקבל ממך משוב

המבוא הזה ייתן לכם טעימה מהאפשרי בעזרת המודולים המובנים. אני מקווה שהתרגשתם! נשמח מאוד אם המפתחים ינסו את המודול של KV Storage (וכן את כל התכונות החדשות שנדונו כאן) ויתנו לנו משוב.

לפניכם הקישורים ל-GitHub שבהם תוכלו לשלוח משוב על כל אחת מהתכונות שמוזכרות במאמר הזה:

אם באתר שלכם נעשה שימוש ב-localStorage כרגע, כדאי לנסות לעבור ל-KV Storage API כדי לבדוק אם הוא עונה על כל הצרכים שלכם. ואם תירשמו לגרסת המקור לניסיון של KV Storage, תוכלו לפרוס את התכונות האלה עוד היום. כל המשתמשים שלך ייהנו מביצועי אחסון טובים יותר, ומשתמשי Chrome 74 ואילך לא יצטרכו לשלם עלויות הורדה נוספות.