Являются ли cookie для чтения/записи атома в браузере

Я пытаюсь реализовать мутекс с перекрестными вкладками для своих нужд. Я нашел реализацию здесь. что кажется весьма перспективным. В принципе, он реализует алгоритм Лесли Лампорта с потребностями атомного чтения/записи для создания мьютекса.

Однако он полагается на localStorage, обеспечивающий атомарное чтение/запись. Это хорошо работает в большинстве браузеров, за исключением Chrome.

Итак, мой вопрос: могу ли я использовать cookie для чтения/записи? Файлы cookie читают/записывают атомы во всех основных браузерах (IE, Chrome, Safari, Firefox)?

Ответ 1

Ни куки, ни localStorage не предоставляют атомные транзакции.

Я думаю, что вы, возможно, неправильно поняли этот пост в блоге, он не говорит, что его реализация не работает в Chrome, но не полагается на localStorage, обеспечивающий атомарное чтение/запись. Он говорит, что обычный localStorage доступ более динамичен в Chrome. Я предполагаю, что это связано с тем, что Chrome использует отдельный процесс для каждой вкладки, тогда как большинство других браузеров, как правило, используют один процесс для всех вкладок. Его код реализует систему блокировки поверх localStorage, которая должна защищать от перезаписываемых вещей.

Другим решением было бы использовать IndexedDB. IndexedDB делает предоставление атомных транзакций. Будучи новым стандартом, он не поддерживается во многих браузерах, таких как localStorage, но он имеет хорошую поддержку в последних версиях Firefox, Chrome и IE10.

Ответ 2

Нет. Даже если браузеры, вероятно, реализуют чтение и запись в cookie, он не защитит вас от изменений, которые происходят между чтением и последующей записью. Это легко увидеть, просмотрев API javascript API для куки файлов, там нет функции мьютекса...

Ответ 3

Я столкнулся с этой проблемой concurrency, используя localStorage сегодня (два года изменил..)

Сценарий. Несколько вкладок браузера (например, Chrome) имеют идентичный код script, который запускается, в основном в одно и то же время (вызываемый, например, SignalR). Код читает и записывает в localStorage. Поскольку вкладки выполняются в разных процессах, но совместно используют общий локальный накопитель, чтение и запись приводят к результатам undefined, так как здесь отсутствует механизм блокировки. В моем случае я хотел убедиться, что только одна из вкладок действительно работает с локальным хранилищем, а не со всеми.

Я попробовал механизм блокировки Бенджамина Думке-фон-дер-Эхе, о котором я говорил в вопросе выше, но получил нежелательные результаты. Поэтому я решил опрокинуть собственный экспериментальный код:

локальная блокировка хранилища:

Object.getPrototypeOf(localStorage).lockRndId = new Date().getTime() + '.' + Math.random();
Object.getPrototypeOf(localStorage).lock = function (lockName, maxHold, callback) {
    var that = this;
    var value = this.getItem(lockName);
    var start = new Date().getTime();    
    var wait = setInterval(function() {
        if ((value == null) || (parseInt(value.split('_')[1]) + maxHold < start)) {
            that.setItem(lockName, that.lockRndId + '_' + start);
            setTimeout(function () {
                if (that.getItem(lockName) == (that.lockRndId + '_' + start)) {
                    clearInterval(wait);
                    try { callback(); }
                    catch (e) { throw 'exeption in user callback'; }
                    finally { localStorage.removeItem(lockName); }
                }
            }, 100);
        }        
    }, 200);        
};

использование:

localStorage.lock(lockName, maxHold, обратный вызов);

  • lockName - глобальное уникальное имя для строки-блокировки
  • maxHold - максимальное время для защиты script в миллисекундах - целое число
  • callback - функция, содержащая защищенный script

пример: "воспроизводить только звук на одной вкладке

//var msgSound = new Audio('/sounds/message.mp3');

localStorage.lock('lock1', 5000, function(){

    // only one of the tabs / browser processes gets here at a time
    console.log('lock aquired:' + new Date().getTime());

    // work here with local storage using getItem, setItem

    // e.g. only one of the tabs is supposed to play a sound and only if none played it within 3 seconds        
    var tm = new Date().getTime();
    if ((localStorage.lastMsgBeep == null)||(localStorage.lastMsgBeep <tm-3000)) {
       localStorage.lastMsgBeep = tm;
       //msgSound.play();                       
       console.log('beep');                        
    }  
});