API Web Locks

Coordinare il lavoro e l'uso delle risorse tra i diversi processi

È ora di chiudere

Le funzioni asincrone in Javascript non sono veramente parallele. A partire da ES2017, Javascript supporta le chiamate di funzione simultanee. La differenza è riassunta molto bene da Madhavan Nagarajan nella seguente dichiarazione (il collegamento può essere trovato nell'addendum).

La concorrenza consiste nell'affrontare molte cose contemporaneamente. Il parallelismo consiste nel fare molte cose contemporaneamente.

L'implementazione della concorrenza di Javascript è ridotta nella sua funzionalità per consentire l'utilizzo di un'API semplice e molto robusta. Le funzioni asincrone non possono essere interrotte e non hanno il concetto di proprietà volatili quando si ha a che fare con l'accesso alla stessa variabile da diverse chiamate asincrone. L'implementazione dettagliata delle funzioni asincrone di ES2017 non rientra nell'ambito di questo articolo, ma il punto principale che voglio spiegare è che fino ad ora il parallelismo non era integrato in Javascript e nel Web e, pertanto, nessuna gestione speciale delle mutazioni parallele del stessa entità. Ma questo cambia ora con l'introduzione della "Web Locks API".

Uno per tutti e tutti per uno

Ora che le app Web progressive offrono vere architetture multithread con l'introduzione di WebWorkers e ServiceWorker, le cose sono cambiate. Il vero parallelismo è possibile nelle app Web e quindi nasce il desiderio di strumenti più sofisticati per gestire il codice parallelo.

Un blocco è un meccanismo per richiedere l'accesso alle risorse e avere la garanzia che solo un processo in qualsiasi momento abbia realmente accesso. Bloccare le risorse in questo modo evita un'ampia serie di aree di conflitto che potrebbero sorgere.

Una risorsa è solo uno spazio dei nomi, identificato da una stringa. E la tua richiesta di accesso alla risorsa è altrettanto semplice, in quanto hai solo bisogno dell'ID e di una funzione di callback, molto probabilmente asincrona, per implementare la "Web Lock API". Quando una funzione asincrona è terminata, il blocco viene rilasciato e altre richieste possono accedervi nuovamente.

/*
 * 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();
}

A causa dello stato sperimentale di questa nuova API, devi considerarla come una funzionalità facoltativa nel tuo codice con un fallback valido disponibile.

/**
 * 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.
  }
}

Per illustrare meglio questa nuova API, daremo un'occhiata a un semplice esempio. Supponiamo che tu abbia una PWA multithread con il tuo processo principale e due WebWorker. La tua app utilizza anche un IndexDB, con codice personalizzato che sincronizza le modifiche da e verso il database con il cloud. Utilizzando la "Web Lock API" in questo scenario, ogni processo può richiedere l'accesso al blocco definito per sincronizzare le modifiche al database, assicurandosi che nessun'altra mutazione venga eseguita durante questa chiamata.

Nota che l'"API Web Lock" non riguarda tanto la mutazione di una singola variabile senza effetti collaterali nella tua app web (anche se questo può essere chiaramente un caso d'uso), ma più la gestione delle chiamate di funzione in un'architettura parallela che altrimenti porterebbe effetti collaterali negativi.

Molto altro da imparare

Questo articolo ha fornito solo un'introduzione alla nuova "API Web Locks", che è attualmente in stato sperimentale e supportata principalmente dai browser basati su Chromium. L'API offre più opzioni che descrivono qui e vale la pena esaminarla.