Являются ли 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');
}
});