ממשק API למנעולי אינטרנט

תיאום העבודה ושימוש במשאבים בין תהליכים שונים

הגיע הזמן לנעול

פונקציות אסינכרוניות ב- Javascript אינן מקבילות באמת. החל מ- ES2017, ל- Javascript יש תמיכה בשיחות פונקציות בו זמנית. את ההבדל מסכם יפה מאוד Madhavan Nagarajan בהצהרה הבאה (קישור ניתן למצוא בתוספת).

במקביל מדובר בהתמודדות עם המון דברים בבת אחת. מקבילות זה לעשות הרבה דברים בבת אחת.

היישום של המקביליות של Javascript מצטמצם בפונקציונליות שלו כדי לאפשר שימוש ב- API פשוט וחזק מאוד. לא ניתן להפריע לפונקציות Async ואין להן מושג של מאפיינים נדיפים כאשר מתמודדים עם גישה לאותו משתנה על ידי שיחות אסינכרוניות שונות. היישום המפורט של פונקציות האסינכרון של ES2017 אינו מחוץ לתחום של מאמר זה, אך הנקודה העיקרית שאני רוצה להעביר היא שעד כה, מקבילות לא הייתה מובנית ב- Javascript ובאינטרנט, ולכן אין טיפול מיוחד במוטציות מקבילות של אותה ישות. אבל זה משתנה כעת עם הצגת ה- "Web Locks API".

אחד בשביל כולם וכולם בשביל אחד

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

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

משאב הוא רק מרחב שמות, שמזוהה על ידי מחרוזת. ובקשתך לגשת למשאב פשוטה באותה מידה, מכיוון שאתה זקוק רק למזהה ולהחזרת פונקציה, ככל הנראה אסינכרוני, בכדי ליישם את ה- "Web Lock API". כאשר פונקציית async אחת הסתיימה המנעול משתחרר ובקשות אחרות יכולות לגשת אליו שוב.

/*
 * A simple demonstration of the Web Lock API.
 * Note that this example has been taken from
 * MDN's awesome documentation, linked in the
 * addendum.
 */
async function foo(){
  // A common async function that you already know.
  const data = await getData();

  // Request the lock.
  // Note that we can simply await the locked call!
  await navigator.locks.request('lock_resource_id', async lock => {
    // The lock has been acquired.
    // At this point, this call has exlusive access 
    // to the resource 'lock_resource_id'.
    await updateDb(data);
    // Now the lock will be released.
  });
  
  // The lock has been released.
  // Continuse with plain async calls.
  await updateUi();
}

בשל המצב הניסויי של ה- API החדש הזה, עליכם להתייחס אליו כאל תכונה אופציונלית בקוד שלכם, עם תגובת חוקית זמינה.

/**
 * Due to the usage of web locks in core parts
 * of your app, actually using the API this way
 * might introduce more problems then it could solve.
 * 
 * Therefore a thorough specification in your app
 * has to be implementation before using this feature.
 */
async function update(){
  if(navigator?.locks){
    // Run logic with lock.
  } else {
    // Use fallback.
  }
}

כדי להמחיש טוב יותר את ה- API החדש הזה, נסתכל על דוגמה פשוטה. נניח שיש לך PWA רב-הברגה עם התהליך העיקרי שלך ושני עובדי רשת. האפליקציה שלך משתמשת גם ב- IndexDB, עם קוד מותאם אישית שמסנכרן שינויים אל ומסד הנתונים עם הענן. באמצעות ה- "Web Lock API" בתרחיש זה, כל תהליך יכול לבקש גישה למנעול המוגדר לצורך סינכרון שינויים למסד הנתונים, ולוודא שאף מוטציה אחרת לא תפעל במהלך שיחה זו.

שים לב ש- "Web Lock API" לא כל כך עוסק במוטציה של משתנה יחיד ללא תופעות לוואי באפליקציית האינטרנט שלך (אם כי זה יכול בבירור להיות מקרה שימוש), אלא יותר על טיפול בשיחות פונקציות בארכיטקטורה מקבילה שאחרת תוביל ל תופעות לוואי שליליות.

הרבה יותר ללמוד

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

הצעות

קשור

נספח

שפות