Назад к блогу
Платформа

Web Locks API: безопасная координация общей работы браузера

Координируйте вкладки, окна и workers через Web Locks API, не смешивая браузерные блокировки с распределёнными серверными блокировками.

BotBrowser Team

Документация

Нужна структурированная документация по теме Платформа?

Эта статья относится к редакционной библиотеке. Для пошаговой настройки, справки и постоянных обновлений переходите сразу в соответствующий раздел docs.

Когда несколько вкладок или workers изменяют один ресурс браузера, проверка перед записью не координирует работу: оба контекста могут пройти проверку одновременно. Web Locks API ставит именованные запросы в очередь, чтобы только один контекст одного origin владел критической секцией. API не координирует серверы или разные origin и сам по себе не исправляет состояние после закрытия приложения. BotBrowser может повторить авторизованный профильный сценарий, но не выдаёт блокировку и не заменяет корректность приложения или сервера.

Абстрактный поток: несколько контекстов браузера сходятся в одну сериализованную критическую секцию и возвращаются к своей работе.

TL;DR

  • Охватывайте блокировкой только минимальную общую операцию и освобождайте её возвратом из callback.
  • Используйте ifAvailable или дедлайн приложения, если ожидание не подходит; отказ не означает получение блокировки.
  • Worker, вкладка или окно могут исчезнуть. Делайте операцию идемпотентной, а восстановление держите вне callback.
  • Web Locks координирует контексты браузера одного origin, но не cross-origin страницы и не серверные процессы.
  • BotBrowser помогает повторять авторизованный профильный сценарий, но семантика блокировки, хранилище и отмена остаются ответственностью страницы.

Содержание

Модель блокировки

navigator.locks.request(name, options, callback) ставит именованную блокировку в очередь. По умолчанию режим эксклюзивный; shared-режим допускает нескольких читателей и исключает эксклюзивного писателя. Callback запускается после выдачи блокировки и удерживает её до возврата или завершения promise. Другой контекст того же origin ждёт в очереди, а не опрашивает флаг в хранилище.

Это не глобальный mutex backend: очередь не пересекает origin, профили, устройства или серверные экземпляры. Критическая секция должна быть короткой: прочитать запись, проверить изменение, записать и вернуть результат. Сетевые вызовы обычно выполняются вне блокировки; долговечное решение требует серверной транзакции или lease.

Небольшой fixture

Fixture увеличивает локальный счётчик и сообщает, получена ли блокировка. При ifAvailable значение lock равно null, если имя занято.

async function incrementCounter(storage, report) {
  if (!navigator.locks) return report('unsupported');
  return navigator.locks.request('counter-write', { ifAvailable: true }, async lock => {
    if (!lock) return report('busy');
    const current = Number(storage.getItem('counter') || 0);
    storage.setItem('counter', String(current + 1));
    report('committed');
  });
}

Два одновременных контекста не входят в секцию вместе; занятый сообщает busy, а браузер без API сообщает unsupported. Это только локальный пример: localStorage не является транзакционной базой. Для важных данных используйте подходящее хранилище и повторно проверяйте конфликт на сервере.

Безопасность worker и восстановление

Worker может запросить то же имя, что и окно. Если его завершить во время ожидания или callback, браузер освободит блокировку, но частичная запись или внешний эффект остаются задачей приложения. Используйте ключ идемпотентности и различайте «не начато», «подтверждено» и «неизвестно после прерывания». Не держите блокировку во время медленного запроса сети.

Не создавайте бесконечную очередь пользовательских действий. ifAvailable подходит необязательному обновлению; обязательной работе нужны дедлайн и проверка отмены перед необратимым шагом. Всегда возвращайтесь из callback и закрывайте порты worker при остановке.

BotBrowser позволяет повторять авторизованные сценарии профиля для проверки совместимости. Он не выдаёт Web Lock, не освобождает блокировку другой вкладки, не управляет меж-origin планированием и не заменяет серверные транзакции.

Доказательства и матрица

Возьмите два окна одного origin и worker, уникальное имя, счётчик и принудительное завершение worker. Запишите версию браузера, профиль, headed/headless, хранилище, видимый результат и итоговое значение; не сохраняйте данные аккаунта или сырые снимки.

НаблюдениеБезопасная трактовкаДействие
Один committed на принятый запросСекция сериализована в этом тестеСохранить короткую секцию и повторить после обновления
busy при ifAvailableВ момент запроса имя занятоСохранить состояние и решить, нужен ли видимый повтор
unsupportedAPI нет в текущем контекстеИспользовать запасной путь или серверную транзакцию
Worker завершился до отчётаРезультат может быть неизвестенСначала сверить ключ идемпотентности
Счётчик неверен при сериализацииХранилище или проверка неатомарныПеренести инвариант в транзакционное хранилище

Fixture показывает наблюдаемое поведение браузера, а не распределённую координацию. Проверяйте также сообщение, сохранённую форму и повтор без дублирования записи.

Граница ресурса и ответственность callback

Имя должно описывать защищённый ресурс, а не экран. Разделяйте разные инварианты и не используйте общий lock для независимой работы. Callback должен прочитать, проверить, записать и вернуть результат; блокировка освобождается после завершения promise. Сеть, ожидание пользователя и анимации выполняются вне lock.

Ошибка освобождает lock, но не доказывает завершение внешнего эффекта. AbortController.abort() не отзывает уже начатый callback: он только сообщает коду, который проверяет signal. Проверяйте отмену перед необратимым шагом и делайте повтор идемпотентным.

Исчезновение владельца и дедлайн

Вкладка, окно или worker могут исчезнуть. Браузер освободит lock, но приложение должно записать намерение с ключом идемпотентности и сверить outbox: отличить не начато, подтверждено и неизвестно перед повтором. При ifAvailable состояние busy сохраняется; обязательной работе нужен дедлайн, а не плотный цикл запросов.

Поддержка и повторная проверка

Разделяйте наличие API, завершение операции и видимый результат. Строка версии браузера не заменяет fixture. Проверяйте отсутствие API, отказ callback, ошибку хранилища и остановку worker; сохраняйте доступный статус и повтор, доступный с клавиатуры. После изменения браузера, хранилища или offline-режима пересмотрите имена, запасной путь и хранение доказательств.

Итог

Web Locks подходит для короткой координации контекстов одного origin. Делайте записи атомарными, восстанавливайте прерывания и храните долговечные инварианты там, где они переживут браузер. Следующий шаг - запустить fixture двух окон и worker с настоящим запасным путём и проверить итоговую запись.

FAQ

Защищает ли Web Lock строку сервера?

Нет. Сервер всё равно отвечает за авторизацию, конфликты и транзакцию или идемпотентность.

Можно ли принудительно освободить блокировку по таймауту?

Нет. Браузер освобождает её после callback или завершения владельца. Проектируйте отмену и не держите медленную работу внутри.

ifAvailable означает ошибку?

Это осознанный отказ от ожидания. null значит, что операция не выполнялась; сохраните состояние и решите, предлагать ли повтор.

Делает ли BotBrowser планирование детерминированным?

Нет. Он делает повторяемым совместимый профильный сценарий, но планирование, хранилище и восстановление остаются ответственностью приложения.

Источники и чтение

Sources

#Web Locks API#Workers#Координация Браузера#Конкурентность

Переведите BotBrowser из исследований в продакшн

Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.