במשך רוב העשור האחרון, ספקי דפדפנים ומומחים לביצועים באינטרנט אומרים שlocalStorage
איטי, ושמפתחי אתרים צריכים להפסיק להשתמש בו.
למען הצדק, האנשים שאומרים את זה לא טועים. localStorage
הוא API סינכרוני שחוסם את ה-thread הראשי, וכל פעם שאתם ניגשים אליו אתם עלולים למנוע מהדף להיות אינטראקטיבי.
הבעיה היא שממשק ה-API של localStorage
פשוט כל כך, והחלופה האסינכרונית היחידה ל-localStorage
היא IndexedDB, שלא ידועה בקלות השימוש או בממשק ה-API הידידותי שלה.
לכן, המפתחים נאלצים לבחור בין משהו שקשה להשתמש בו לבין משהו שפוגע בביצועים. אמנם יש ספריות שמציעות את הפשטות של ממשק ה-API localStorage
, אבל בעצם משתמשות בממשקי API לאחסון אסינכרוני, אבל הוספת אחת מהספריות האלה לאפליקציה כרוך בעלות שמבוססת על גודל הקובץ, ויכולה לפגוע בתקציב הביצועים.
אבל מה אם אפשר היה לקבל את הביצועים של ממשק API לאחסון אסינכרוני עם הפשטות של ממשק ה-API localStorage
, בלי לשלם על הגודל של הקובץ?
יכול להיות שבקרוב כן. אנחנו ב-Chrome מנסים תכונה חדשה שנקראת מודולים מובנים, והמודול הראשון שאנחנו מתכננים להשיק הוא מודול אחסון אסינכרוני של מפתח/ערך שנקרא KV Storage.
אבל לפני שאכנס לפרטים של מודול האחסון של KV, אסביר מה הכוונה למודולים מובנים.
מהם מודולים מובנים?
מודולים מובְנים הם כמו מודולים רגילים של JavaScript, אלא שלא צריך להוריד אותם כי הם מגיעים עם הדפדפן.
כמו ממשקי API רגילים לאינטרנט, גם מודולים מובנים צריכים לעבור תהליך סטנדרטיזציה – לכל אחד מהם תהיה מפרט משלו, שדורש בדיקת עיצוב וסימנים חיוביים לתמיכה גם ממפתחי אינטרנט וגם מספקי דפדפנים אחרים, לפני שהוא יוכל להימסר. (ב-Chrome, מודולים מובנים יעברו את אותו תהליך השקה שבו אנחנו משתמשים כדי להטמיע ולשלוח את כל ממשקי ה-API החדשים).
בניגוד לממשקי API רגילים לאינטרנט, מודולים מובנים לא חשופים ברמת ה-global – הם זמינים רק דרך ייבוא.
יש הרבה יתרונות לאי-חשיפת מודולים מובנים ברמת ה-global: הם לא יוסיפו עלויות נוספות להפעלת הקשר חדש של סביבת זמן ריצה של JavaScript (למשל, כרטיסייה, worker או service worker חדשים), והם לא יצרכו זיכרון או מעבד אלא אם הם מיובאים בפועל. בנוסף, הם לא חושפים אתכם לסיכונים של התנגשויות בשמות עם משתנים אחרים שמוגדרים בקוד.
כדי לייבא מודול מובנה, משתמשים בקידומת std:
ואחריה במזהה של המודול המובנה. לדוגמה, בדפדפנים נתמכים, אפשר לייבא את מודול KV Storage באמצעות הקוד הבא (כאן מוסבר איך משתמשים ב-polyfill של KV Storage בדפדפנים לא נתמכים):
import storage, {StorageArea} from 'std:kv-storage';
מודול KV Storage
המודול של KV Storage דומה בפשטותו ל-localStorage
API, אבל צורת ה-API שלו דומה יותר ל-JavaScript Map
.
במקום getItem()
, setItem()
ו-removeItem()
, מוצגים get()
, set()
ו-delete()
.
יש לה גם שיטות אחרות שדומות למפות, שלא זמינות ל-localStorage
, כמו keys()
, values()
ו-entries()
. כמו ב-Map
, המפתחות שלה לא חייבים להיות מחרוזות. הם יכולים להיות כל סוג שניתן לסדר בסדרה.
בניגוד ל-Map
, כל השיטות של KV Storage מחזירות promises או מחזורים אסינכרונים (כי הנקודה העיקרית של המודול הזה היא שהוא לא סינכרוני, בניגוד ל-localStorage
). כדי לראות את ה-API המלא בפירוט, אפשר לעיין במפרט.
כפי שראיתם בדוגמת הקוד שלמעלה, למודול KV Storage יש ייצוא אחד שמוגדר כברירת מחדל storage
וייצוא אחד בעל שם StorageArea
.
storage
הוא מופע של המחלקה StorageArea
בשם 'default'
, והוא מה שמפתחים ישתמשו בו בתדירות הגבוהה ביותר בקוד האפליקציה שלהם. הכיתה StorageArea
נועדה למקרים שבהם יש צורך בבידוד נוסף (למשל, ספרייה של צד שלישי ששומרת נתונים ומבקשת למנוע התנגשויות עם נתונים שנשמרים דרך מופע storage
ברירת המחדל). נתוני StorageArea
מאוחסנים במסד נתונים של IndexedDB בשם kv-storage:${name}
, כאשר 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
.
לכן, כשהדפדפן נתקל בהצהרת ייבוא שמפנה לכתובת ה-URL הזו (/path/to/kv-storage-polyfill.mjs
), הוא מנסה קודם לטעון את std:kv-storage
, ואם הוא לא מצליח, הוא עובר לטעינה של /path/to/kv-storage-polyfill.mjs
.
שוב, הקסם הוא שהדפדפן לא צריך לתמוך במפות ייבוא או במודולים מובנים כדי שהשיטה הזו תפעל, כי כתובת ה-URL שמועברת להצהרת הייבוא היא כתובת ה-URL של ה-polyfill. ה-polyfill הוא לא חלופה, אלא ברירת המחדל. המודול המובנה הוא שיפור הדרגתי.
מה קורה בדפדפנים שלא תומכים במודולים בכלל?
כדי להשתמש במפות ייבוא כדי לטעון מודולים מובנים באופן מותנה, צריך להשתמש בפועל בהצהרות import
. המשמעות היא שצריך להשתמש גם בסקריפטים של מודולים, כלומר ב-<script type="module">
.
נכון לעכשיו, יותר מ-80% מהדפדפנים תומכים במודולים. בדפדפנים שלא תומכים במודולים, אפשר להשתמש בשיטת module/nomodule כדי להציג חבילת קוד מדור קודם. חשוב לזכור שכדי ליצור את הגרסה המאוחדת (build) של nomodule
, צריך לכלול את כל ה-polyfills, כי ברור שדפדפנים שלא תומכים במודולים לא תומכים במודולים מובנים.
הדגמה של KV Storage
כדי להמחיש שאפשר להשתמש במודולים מובנים ועדיין לתמוך בדפדפנים ישנים יותר, הכנתי דמו שמשתמש בכל השיטות המתוארות למעלה ופועל בכל הדפדפנים הקיימים:
- בדפדפנים שתומכים במודולים, בייבוא מפות ובמודול המובנה לא נטען קוד מיותר.
- בדפדפנים שתומכים במודולים ובייבוא מפות, אבל לא תומכים במודול המובנה, נטען הפוליפילי של KV Storage (דרך מערך הטעינה של המודולים בדפדפן).
- בדפדפנים שתומכים במודולים אבל לא תומכים במפות ייבוא, מתבצע גם טעינת ה-polyfill של KV Storage (דרך מערך הטעינה של המודולים בדפדפן).
- בדפדפנים שלא תומכים במודולים בכלל, ה-polyfill של KV Storage מופיע בחבילה הקודמת (שנטענת דרך
<script nomodule>
).
הדמו מתארח ב-Glitch, כך שאפשר לעיין במקור שלו. יש לי גם הסבר מפורט על ההטמעה בREADME. אם אתם רוצים לראות איך הוא נבנה, אתם מוזמנים.
כדי לראות את המודול המובנה המקורי בפעולה, צריך לטעון את ההדגמה ב-Chrome בגרסה 74 ואילך כשהדגל של התכונות הניסיוניות של פלטפורמת האינטרנט מופעל (chrome://flags/#enable-experimental-web-platform-features
).
אפשר לוודא שהמודול המובנה נטען כי סקריפט ה-polyfill לא יופיע בחלונית המקור ב-DevTools. במקום זאת, תוצג גרסת המודול המובנה (עובדה מעניינת: אפשר לבדוק את קוד המקור של המודול ואפילו להוסיף לו נקודות עצירה!):
נשמח לקבל ממך משוב
המבוא הזה נועד לתת לכם טעימה ממה שאפשר לעשות באמצעות מודולים מובנים. אנחנו מקווים שהתכונה הזו תגרום לך להתרגש. אנחנו מזמינים את המפתחים לנסות את המודול KV Storage (וגם את כל התכונות החדשות שצוינו כאן) ולשלוח לנו משוב.
אלה הקישורים ל-GitHub שבהם אפשר לשלוח לנו משוב על כל אחת מהתכונות שמפורטות במאמר הזה:
אם האתר שלכם משתמש כרגע ב-localStorage
, כדאי לנסות לעבור ל-KV Storage API כדי לראות אם הוא עונה על כל הצרכים שלכם. אם נרשמתם לתקופת הניסיון של KV Storage origin, תוכלו לפרוס את התכונות האלה כבר היום. כל המשתמשים שלכם אמורים ליהנות מביצועי אחסון טובים יותר, ומשתמשי Chrome בגרסה 74 ואילך לא יצטרכו לשלם עלויות הורדה נוספות.