Время запереться
Асинхронные функции в Javascript не совсем параллельны. Начиная с ES2017, Javascript поддерживает одновременные вызовы функций. Разница очень хорошо резюмирована Мадхаваном Нагараджаном в следующем утверждении (ссылку можно найти в приложении).
Параллелизм - это одновременная работа с множеством вещей. Параллелизм - это одновременное выполнение множества задач.
Реализация параллелизма Javascript ограничена в своей функциональности, чтобы можно было использовать простой и очень надежный API. Асинхронные функции не могут быть прерваны и не имеют понятия изменчивых свойств при доступе к одной и той же переменной с помощью разных асинхронных вызовов. Подробная реализация асинхронных функций ES2017 выходит за рамки этой статьи, но главный момент, который я хочу уточнить, заключается в том, что до сих пор параллелизм не был встроен в Javascript и Интернет, и, следовательно, не было специальной обработки параллельных мутаций одно и то же лицо. Но теперь это меняется с появлением «API веб-блокировки».
Один за всех и все за одного
Теперь, когда прогрессивные веб-приложения предлагают вам настоящую многопоточную архитектуру с появлением WebWorkers и ServiceWorker, все изменилось. Настоящий параллелизм возможен в веб-приложениях, поэтому возникает потребность в более сложных инструментах для работы с параллельным кодом.
Блокировка - это механизм запроса доступа к ресурсам и гарантия того, что только один процесс в любой момент времени действительно имеет доступ. Подобная блокировка ресурсов позволяет избежать множества конфликтных ситуаций, которые могут возникнуть в противном случае.
Ресурс - это просто пространство имен, идентифицируемое строкой. И ваш запрос на доступ к ресурсу так же прост, поскольку вам нужен только идентификатор и обратный вызов функции, скорее всего асинхронный, для реализации «Web Lock API». Когда одна асинхронная функция завершает работу, блокировка снимается, и другие запросы снова могут получить к ней доступ.
/*
* 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 с вашим основным процессом и двумя WebWorkers. Ваше приложение также использует IndexDB с настраиваемым кодом, который синхронизирует изменения в базе данных и из нее с облаком. Используя «Web Lock API» в этом сценарии, каждый процесс может запросить доступ к определенной блокировке для синхронизации изменений в базе данных, гарантируя, что никакие другие мутации не будут запущены во время этого вызова.
Обратите внимание, что «API веб-блокировки» не столько касается изменения одной переменной без побочных эффектов в вашем веб-приложении (хотя это явно может быть вариантом использования), но больше касается обработки вызовов функций в параллельной архитектуре, что в противном случае привело бы к отрицательные побочные эффекты.
Гораздо больше узнать
В этой статье дается только введение в новый «Web Locks API», который в настоящее время находится в экспериментальном состоянии и в основном поддерживается браузерами на основе Chromium. API предлагает больше опций, которые описаны здесь, и их стоит изучить.