Javascript.RU

Хранение данных на клиенте. DOM Storage и его аналоги.

По мере того как web-странички превращаются в AJAX-приложения, им требуются все новые возможности.

Сложные выборки элементов DOM обеспечиваются некоторыми браузерами и почти всеми распространенными Javascript-фреймворками.

Кросс-доменные HTTP-запросы находят поддержку в стандартах и реализуются в новейших браузерах, включая Internet Explorer 8.

В этой статье пойдет речь о средствах для хранения большого количества данных на клиенте, в браузере, которые доступны уже сейчас.

В частности, Internet Explorer 5+, Firefox 2+, Safari 2+ не требуют для этого дополнительных плагинов и Flash.

UPDATE: статья устарела и будет переписана.

Почти во всех браузерах есть поддержка cookies.

На протяжении долгого времени cookies были единственным кросс-браузерным способом сохранить данные, которые будут доступны после перезагрузки страницы.

Однако у cookie есть две важных особенности:

  1. Не более 2 килобайт данных
  2. Данные идут на сервер при каждом HTTP-запросе

Средства хранения на клиенте предусматривают сотни килобайт и мегабайты данных, и не отсылают их на сервер при каждом HTTP-запросе.

А cookie можно продолжать использовать, например, для хранения сессии.

Firefox реализует стандарт хранения "Client-side session and persistent storage of name/value pairs", предложенный в спецификации HTML 5.

Для постоянного хранения данных в нем используется объект window.globalStorage[домен], операции над которым можно производить точно так же, как над обычным javascript-объектом. При уходе с сайта и даже закрытии браузера globalStorage не меняется, так что все его свойства можно прочитать обратно.

Например:

storage = globalStorage[document.domain]

// записать значение
storage['userName'] = 'Vasya'
// прочитать значение
alert(storage['userName'])
// удалить значение
delete storage['userName']

// получить все значения
for(var name in storage) {
    alert(name + ':' + storage[name])
}

При чтении/записи на элементе body инициируется всплывающее событие storage.

Поймать его можно, например, таким обработчиком:

window.addEventListener('storage', function(event) { ... })

Стандарт HTML 5 все еще в процессе развития. В старой редакции прочитанные значения имели тип StorageItem.

Версия Firefox 2.0.0.13 возвращает при чтении объект именно этого типа.

Из текущей редакции StorageItem убран. В ней возвращаемые хранилищем значения имеют более простой тип DOMString.

..А пока эти изменения не учтены разработчиками, рекомендуется преобразовать значения к String явным образом.

Например:

var test = "12345"
storage.test = test // сохранить -> String
test = storage.test // прочитать <- StorageItem

alert(test.length) // undefined, это же не строка
alert(test.constructor) // StorageItem

test = String(test) // сделали строку. Теперь все ок.

Ограничения на данные: ключи и значения - только строки.

Размер: 5MB на домен.

Ограничения безопасности - точно такие же, как на cookie.
Данные в globalStorage['site.ru'] можно сохранить только на самом site.ru, а прочитать - на blog.site.ru, но не на otherhost.ru.

Internet Explorer 8 реализует DOM Storage, в то время как версии начиная от 5й поддерживают собственный интерфейс: userData behavior.

Он работает посредством выделенного DOM-элемента, которому назначается behavior userData. В этот элемент загружается нужное пространство имен, и данные становятся доступны через атрибуты.

<span id="storageElement"></span>
<script>    
    storage = document.getElementById('storageElement')
    if (!storage.addBehavior) {
        alert("userData not available.")
    } else {
        // поставить userData behavior
        storage.addBehavior("#default#userData")
        // загрузить пространство имен
        storage.load("namespace")    
    }
</script>

После инициализации можно работать с данными. Для записи изменений используется метод save.

function put(key, value) { // записать значение
    storage.setAttribute(key, value)
    storage.save("namespace")
}

function get(key) { // получить значение
    return storage.getAttribute(key)
}

function remove(key) { // удалить значение
    storage.removeAttribute(key)
    storage.save("namespace")
}

Как это часто бывает с Internet Explorer, некоторые операции делаются неочевидным образом.

Так, например, получить все сохраненные данные из storage.attributes нельзя. Там хранятся только атрибуты самого HTML-элемента.

Данные же хранятся в свойстве storage.XMLDocument.documentElement.attributes.

Например, следующий код создает список вида ключ:значение.

var list = []
var attrs = storage.XMLDocument.documentElement.attributes
        
for(var i=0; i<attrs.length; i++) {
    list.push(attrs[i].name+':'+attrs[i].value);
}

В отличие от DOM Storage, можно задать атрибут expires. Он устанавливается на уровне всего элемента и действует на все хранящиеся данные. Очистка данных происходит при вызове load.

var time = new Date(); // Start Time
time.setMinutes(time.getMinutes() + 1)
storage.expires = time.toUTCString();

Ключи и значения - только строки.

Способ работает при всех уровнях безопасности, кроме "Высокого".
При этом для сайтов в зоне Internet объем ограничен 128K на страницу и 1024K на домен, для локальных и интранет - лимит увеличен.

Ограничения безопасности - та же директория, тот же домен и протокол.

Дальше всех в поддержке стандарта хранения пошли разработчики WebKit.
В Safari реализовано локальное хранение в базе данных SQLite.

Набор операций включает в себя CREATE TABLE, INSERT, SELECT, REPLACE, индексы и многое другое, с рядом ограничений безопасности (например, нет LOAD DATA INFILE).

В отличие от DOM Storage и userData, этот интерфейс асинхронный. Все функции запросов к базе данных принимают в качестве аргументов две функции: callback - для обработки результатов и errback - для обработки ошибок.

Когда запрос завершается, вызывается один из этих обработчиков.

Продемонстрируем это на тестовой базе.

db = openDatabase("Test", "1.0", "Webkit Storage Example")

db.transaction(function(tx) {
  tx.executeSql(
      "CREATE TABLE IF NOT EXISTS test (key TEXT, value TEXT, unique(key))", 
      [], 
      function(tx, result) { alert("Success!") },
      function(tx, error) { alert("Failure: "+error.message }
  )
})

Сложновато с первого взгляда?

db.transaction создает транзакцию и передает ее функции-аргументу.

Код внутри function(tx) выполняется в одной транзакции.

Вызов tx.executeSql принимает аргументы:

  1. Запрос
  2. Аргументы подстановки
  3. Обработчик результата
  4. Обработчик ошибки

Следующий пример демонстрирует обработку запроса.

db.transaction(function(tx) {
  tx.executeSql("SELECT value FROM test WHERE key=?", [key],
    function(tx,result) {
      alert("Количество результатов: "+result.rows.length)
      alert("Поле value первого результата: "+ result.rows.item(0).value)
   },
   function(tx, error) { alert("Error!") }
  )
})

Стандарт SQL-хранения также включает в себя поддержку версий схемы, указание размера базы данных в openDatabase и многое другое. Может существовать только одна версия схемы одновременно.

База существует только в рамках домена(полного домена, origin), на котором была создана. Поддомен не имеет доступа к базе домена.

На момент написания статьи разработчики WebKit планировали поддержку DOM Storage, но в nightly build ее не было.

На момент написания статьи Opera 9.5 (beta) не поддерживает ни DOM Storage ни Database Storage.

С другой стороны, разработчики планируют эту поддержку включить.

Там, где нет DOM Storage, для offline-хранения используют flash-интерфейс SharedObject. Он позволяет хранить самые разные объекты средствами Adobe Flash.

Пример ActionScript для работы с SharedObject:

// создать/получить namespace storage
storage = SharedObject.getLocal("storage"); 

// записать данные name => Вася
storage.data.name="Вася";

// сохранить объект
storage.flush()

// перечислить свойства объекта
for (var name in storage.data) {
    trace(name + ":" + storage.data[name])
}

Чтобы работать с этим хранилищем из javascript, нужен способ коммуникации JS<->Flash.

В старых версиях Flash вызвать javascript можно через getURL('javascript:...').

Передать значение во Flash можно установкой переменной flash-объекту. Эту переменную flash-ролик может считывать каждый кадр и предпринимать соответствующие действия.

Во Flash 8+ появился интерфейс ExternalInterface, который позволяет как указывать AS-функцию для приема данных из JS, так и напрямую вызывать JS-метод.

Открыть рабочий пример передачи значения Flash <-> JS.

Код примера в ActionScript:

import flash.external.*;

// установить местную функцию recieveFromJS для приема данных
// от javascript-функции sendFromJS
ExternalInterface.addCallback("sendFromJS", null, recieveFromJS);

// Эта функция будет реагировать на sendFromJS
function recieveFromJS(text) {
    _root.theText.text = text; // .. и устанавливать текст в окошке
}

// Это действие, наоборот, отправляет данные в JS.
_root.button.onRelease = function() {
    // вызвать javascript-функцию recieveFromFlash
    ExternalInterface.call("recieveFromFlash", _root.theText.text);
    _root.theText.text = "";
}

Код примера в JS:

function recieveFromFlash(Txt) {
	document.getElementById('text').value = Txt;
}

function sendFromJS() {
    var value = document.getElementById('text').value
    
    var movie = (navigator.appName.indexOf("Microsoft")!=-1 ? window : document)["BridgeMovie"]    
    
    movie.sendFromJS(value);    

    document.getElementById('text').value = ''
}

Скачать исходники

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

Доступ к SharedObject ограничен роликами с того же домена.

Это принципиально отличается от Javascript, в котором доступ определяется адресом страницы а не скрипта, и делает возможным разного рода кросс-доменные трюки.

Ограничение по умолчанию на размер данных - в районе 100Kb, пользователь может уменьшить или увеличить его в специальном Flash-интерфейсе, который открывается при вызове ActionScript:

System.showSettings(1);

Во-первых, надо иметь Flash. Хранилище доступно только после инициализации Flash-ролика.

Много ошибок в различных версиях Flash затрагивают ExternalInterface, включая повреждение данных во время передачи JS->Flash.

Проще всего узнать о них:

Много работы над обходом багов провел Brad Neuberg для flash-хранилища в dojo:

  • dojox/storage - различные хранилища, включая flash
  • dojox/flash - кроссбраузерная js/flash коммуникация, необходима для dojox/storage

DOM Storage и аналогичные системы хранения - важный шаг к offline-работе web-приложений.

DOM Storage поддерживается всеми современными браузерами.

Интересным сектором для интеграции могут быть CRM-системы с нестабильным интернетом. Например, мини-точка продаж, в которой основная работа идет через интеренет, но хранение текущих договоров дублируется на рабочей машине.

Offline-хранилище может быть использовано для сохранения сложных состояний интерфейса - размеров окон, контрольных элементов и т.п.

Все изменения интерфейса посетителем мгновенно сохранятся в DOM Storage и восстановятся при следующем заходе на страницу без дополнительных механизмов сохранения интерфейса на сервере.

При этом объем хранимого состояния интерфейса вряд ли превысит ограничение в сотни килобайт. Идеальный объект для DOM Storage, не правда ли ?..


Автор: Илья Кантор, дата: 25 мая, 2008 - 17:21
#permalink

dojo svn, похоже, закрылся или переместился. Поменял ссылку на путь внутри dojo.


Автор: Гость (не зарегистрирован), дата: 19 июня, 2008 - 13:19
#permalink

Данные, в globalStorage['site.ru'] можно сохранить только на самом site.ru, а прочитать - на blog.site.ru...

В FF3 данную возможность убрали по соображениям безопастности.


Автор: Гость (не зарегистрирован), дата: 29 августа, 2008 - 15:15
#permalink

у меня в FF3 не сработал пример с хранилищем


Автор: Евгений (не зарегистрирован), дата: 15 октября, 2008 - 12:10
#permalink

Мне на запись

var storage = globalStorage[document.domain];

Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17 выдал ошибку Security error" code: "1000


Автор: Илья Кантор, дата: 15 октября, 2008 - 14:40
#permalink

Примеры на сайте работают в FF3 и FF2 у меня (FF2,3 под Linux).


Автор: Алексей (не зарегистрирован), дата: 30 октября, 2008 - 07:48
#permalink

storage.load("namespace") - на это строке выкидывает ошибку "разрешение отклонено"


Автор: Дмитрий) (не зарегистрирован), дата: 13 ноября, 2008 - 16:08
#permalink

DOM Storage и аналогичные системы хранения - важный шаг к offline-работе web-приложений.


Автор: yak2689 (не зарегистрирован), дата: 3 декабря, 2008 - 14:48
#permalink

Странная эта штука - DOM Storage - для одного НТML-документа
в Mozilla своя память, в IE-своя и, находясь на одной машине, друг друга не видят.
Можно ли в среде НТML/JS писать/читать определенный
(текстовый) файл, как это делается, например, в Си (Си++)?
Вообще, как подать параметры/данные из одного НТML-документа
в другой? Можно ли клиент-скрипт написать на Си (Си++)?


Автор: macint0sh, дата: 27 сентября, 2009 - 01:41
#permalink

Уж если я правильно понял, то суть проблемы описываемой в статье, это хранение данных(объемом большим чем позволенный в cookies) на клиенте, ну и так сказать наиболее удобный для этого подход.
Как выше говорилось, почему бы не использовать google gears?
Ну и насколько я знаю, есть вот такое чудо, TaffyDB, которое решает все проблемы кроссбраузерности при этом предоставляя удобный интерфейс для работы с данными.
Возможно неправильно понял суть, поправьте...


Автор: Snipe, дата: 1 октября, 2009 - 10:57
#permalink

А какие ограничения на название ключа? Например () нельзя использовать, а что еще?


Автор: Гость (не зарегистрирован), дата: 19 ноября, 2009 - 20:53
#permalink

Ещё ссылки на некоторые библиотеки для работы с локальными хранилищами:
YUI 2: Storage Utility
The Dojo Offline Toolkit
iLocalStorage
jStore


Автор: творожок (не зарегистрирован), дата: 1 декабря, 2009 - 00:30
#permalink

или я дурак или лыжи не едут. нет у меня в FireFox в версии 3.0.13 никакого globalStorage. В итоге кроме ошибки ничего данные скрипты не дают.


Автор: творожок (не зарегистрирован), дата: 1 декабря, 2009 - 01:26
#permalink

А в ишаке работает!


Автор: Lexi, дата: 28 декабря, 2009 - 15:05
#permalink

К альфе Opera 10.50 таки прикрутили DOM Storage и Database Storage.


Автор: Илья Кантор, дата: 28 декабря, 2009 - 18:31
#permalink

Ну и новость!


Автор: мамбет (не зарегистрирован), дата: 16 февраля, 2010 - 22:12
#permalink

Братан, тебе надо переписать статью.

Выкинуть все из статьи и описать window.localStorage.

Так как эта штука поддерживается FF 3.6, Opera 10.5, IE 8.0, Сhrome 4.0, Safari 4.0. Сейчас проверил, работает window.localStorage во всех этих браузерах. А для старых IE 6-7 оставить твое описание userData.


Автор: Гость (не зарегистрирован), дата: 8 марта, 2010 - 20:01
#permalink

респект, мамбет!
psкак однако полезно читать каменты (иногда)


Автор: Гость (не зарегистрирован), дата: 19 марта, 2010 - 10:45
#permalink

>все еще приходится использовать нужен
поправьте или не поправляйте. как хотите.


Автор: Хулиос (не зарегистрирован), дата: 26 апреля, 2010 - 19:54
#permalink

Здравствуйте, уважаемые!

Я намереваюсь использовать DOM Storage (Firefox) для хранения небольшой базы данных своего скрипта для Greasemonkey.

Задался вопросом: "А где же все эти данные находятся физически?"

У меня будет около 300-от записей (в каждой от 5-ти до 10-ти "ячеек").
Хотелось бы обнаружить этот файлик и сделать его резервную копию.

Это возможно?


Автор: Хулиос (не зарегистрирован), дата: 26 апреля, 2010 - 21:34
#permalink

Нашел:
C:\Documents and Settings\Администратор\Application Data\Mozilla\Firefox\Profiles\s6v6hjub.default\webappsstore.sqlite


Автор: AlexKF (не зарегистрирован), дата: 3 декабря, 2010 - 14:22
#permalink

Так, ребят, скаже чесно, в данном вопросе я вобще не бум бум, но понятно вещь нужная.
есть один ресурс, тяжёлый слегка, так вот , как и что именнно надо сделать, чтобы Опера стала его воспринемать как "хранилище" ??
какой скрипт там, тег , код или что ?
если не затруднит ответ по почте !!
спасибо за ранее.

P.S. www.vesti.ru - тоже не файл обменник и не хост, а Опера его видит как хранилище, и после этого открывает легче и быстрее.


Автор: Гость (не зарегистрирован), дата: 12 января, 2011 - 00:05
#permalink

В крайнем драфте html5 storage остаются sessionStorage и localStorage. Обе работают в FF а в остальном печально.


Автор: Гость (не зарегистрирован), дата: 4 февраля, 2011 - 21:19
#permalink

Осторожно используйте window name т.к. в него могут попасть данные с другого сайта, если он был открыт в том же табе. Ссылка на увеличители членов, например. Или sql-инъекция. Почитайте про xss кто не знает.


Автор: Лидер нации (не зарегистрирован), дата: 14 марта, 2011 - 10:34
#permalink

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

По этой причине я не вижу другого смысла в локальном хранении данных, кроме как для поддержки оффлайновой работы сайта. Может меня кто-нибудь поправить?


Автор: edd_k, дата: 15 апреля, 2011 - 03:23
#permalink

мануал по localStorage на MSDN:
http://msdn.microsoft.com/ru-ru/library/cc197062(v=vs.85).aspx


Автор: bunda1 (не зарегистрирован), дата: 7 марта, 2012 - 20:21
#permalink

На Firefox 13.0a1 вдруг перестала работать globalStorage
консоль пишет: Error: globalStorage is not defined
и такой код уже не работает:

storage = globalStorage[document.domain]

// записать значение
storage['userName'] = 'Vasya'
// прочитать значение
alert(storage['userName'])

в чем причина и чем заменить globalStorage


Автор: bunda1 (не зарегистрирован), дата: 7 марта, 2012 - 20:38
#permalink

На Firefox 13.0a1 вдруг перестала работать globalStorage

"Use of globalStorage is deprecated. Please use localStorage instead"


Автор: Bafla, дата: 19 января, 2013 - 09:34
#permalink

Firefox (Gecko) не стандарт. В их руководстве так прямо и сказано. Одно удивляет:- воткнул скрипт что писал для firefox а он полностью работоспособен в опере приятно было.


Автор: Bafla, дата: 19 января, 2013 - 09:39
#permalink

Вот чего получилось, если требуется независимая переменная

//первый старт?
function start () {
var seychas=sessionStorage.getItem("start");
if (seychas){
}
else {
sessionStorage.setItem("seychas", 0);
}

}

Автор: Гость (не зарегистрирован), дата: 6 апреля, 2013 - 10:05
#permalink

почему в стати указан размер cookies 2 kb
"Однако у cookie есть две важных особенности:

Не более 2 килобайт данных"


Автор: Гость (не зарегистрирован), дата: 23 сентября, 2015 - 22:39
#permalink

в примере ошибка, если кому вдруг пригодится, вот рабочий пример:

db = openDatabase("Test", "1.0", "Webkit Storage Example"," 5 * 1024 * 1024")

db.transaction(function(tx) {
tx.executeSql(
"CREATE TABLE IF NOT EXISTS test (key TEXT, value TEXT, unique(key))",
[],
function(tx, result) { alert("Success!") },
function(tx, error) { alert("Failure: "+error.message) }
)
})


Автор: Patsy J. Moore (не зарегистрирован), дата: 10 октября, 2019 - 12:29
#permalink

Some genuinely interesting points you have written. mobile legends


Автор: suka chu (не зарегистрирован), дата: 16 октября, 2019 - 10:43
#permalink

It's great to be here with everyone, I have a lot of knowledge from what you share, to say thanks, the information and knowledge here helps me a lot. driving directions


Автор: Гость (не зарегистрирован), дата: 21 марта, 2020 - 06:12
#permalink

The article I am looking for. Your article gives me another approach on this topic. I hope to read more articles from you.

vin lookup


Автор: keto diet pills amazon (не зарегистрирован), дата: 28 мая, 2020 - 09:20
#permalink

Thank you so much for ding the impressive job here, everyone will surely like your post. https://ketobodytones.com/keto-diet-pills-amazon/


Автор: buy medicines online (не зарегистрирован), дата: 4 июня, 2020 - 13:48
#permalink

I really enjoy reading and also appreciate your work.
https://propharmacystores.com


Автор: telemarketing leads (не зарегистрирован), дата: 18 июня, 2020 - 13:37
#permalink

Australian telemarketing leads is one of the top providers of telemarketing lists and lead generation services globally. Contact them today for a free sample of b2b or b2c lists.https://australiantelemarketingleads.net/


Автор: roblox hack (не зарегистрирован), дата: 5 июля, 2020 - 12:49
#permalink

Thank you for this wondeful idea this is an awesome idea for the user of roblox game.
roblox hack


Автор: goldavenue (не зарегистрирован), дата: 18 июля, 2020 - 10:30
#permalink

good news for everyone many of them are waiting for such kind of good news which we are sharing here. that is saya gold avenue possession date should be announced soon in this year all the residents would


Автор: Keto pills (не зарегистрирован), дата: 11 августа, 2020 - 09:19
#permalink

Thank you for your post, I look for such article along time, today i find it finally. this post give me lots of advise it is very useful for me. Keto pills


Автор: tree removal fort worth (не зарегистрирован), дата: 12 августа, 2020 - 10:48
#permalink

great article really like your content..and love to share with my friends list..
tree removal fort worth


Автор: hannahberry (не зарегистрирован), дата: 13 августа, 2020 - 11:28
#permalink

Interesting and interesting content is covered by the website. Do it better and more readers will visit your article.
geometry dash


Автор: kuita (не зарегистрирован), дата: 1 сентября, 2020 - 07:35
#permalink

Hi there, I found your blog via Google while searching for such kinda informative post and your post looks very interesting for me. run 3


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2020 - 18:46
#permalink

Wow the blog you give us is amazing, no wonder many people want to read this. https://celebrityinsider.org/


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2020 - 18:48
#permalink

I will recomend this blog to all of my friends. Great article.
https://happygamer.com/


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2020 - 18:50
#permalink

Thank you for this inspiring blog. I wait for more
https://ballstepded.com/


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2020 - 18:50
#permalink

I learned so much from this blog. Good inforamtion. https://fixoserror.com/


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2020 - 18:50
#permalink

I wait for more.Great article.
https://premiereretail.com


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2020 - 18:51
#permalink

I stumbled across this blog.Great article. https://tecsprint.com


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2020 - 18:52
#permalink

Thank you for this amazing blog. Congratulations.
https://howtolose10poundsinaweek.com


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2020 - 18:52
#permalink

The things i see here are very informative. Keep going. https://bargainistafashionista.com


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2020 - 18:52
#permalink

I can say that is one of the best articles out on the internet. https://bankncard.com


Автор: Гость (не зарегистрирован), дата: 9 сентября, 2020 - 18:53
#permalink

I readed all the article. So informative https://vhan.net


Автор: Гость (не зарегистрирован), дата: 10 сентября, 2020 - 16:21
#permalink

This is one of the best sites i have found on the internet until now. Nice article keep going.
https://millikenconstructioninc.com/


Автор: Гость (не зарегистрирован), дата: 11 сентября, 2020 - 16:15
#permalink

Thanks for the information, very clear and simple. I will try to use it.Love the way you write. Working my way through your article links
https://vvhen.to/


Автор: Гость (не зарегистрирован), дата: 15 сентября, 2020 - 12:09
#permalink

This is one of the best articles i found on the blogs around the internet. I am really interested in seeing more of this. Keep going with the great work!
https://gzgjskpzz1m.ga


Автор: Гость (не зарегистрирован), дата: 19 сентября, 2020 - 10:56
#permalink

First of all ,you have picked a very unique theme . I think i might design something similar for a future project that i want to build .
On top of that ,i in truth enjoy most of your content pieces and your different point of view.
Thank you https://seoconsultants24.blogspot.com/


Автор: Гость (не зарегистрирован), дата: 19 сентября, 2020 - 11:34
#permalink

Nice information, many thanks to the author. It is incomprehensible to me now, but in general, the usefulness and significance is overwhelming.https://seokarma24.blogspot.com/


Автор: Гость (не зарегистрирован), дата: 19 сентября, 2020 - 15:20
#permalink

I have reviewed the article many times and I find it very impressive. The information is extremely useful especially the last part I care about that information very much. I have been looking for this certain information for a long time.
https://packseo.blogspot.com/


Автор: Гость (не зарегистрирован), дата: 23 сентября, 2020 - 16:58
#permalink

I’m gone to tell my little brother, that he should
also pay a quick visit this blog on regular basis to take updated from hottest information.
https://connectorseo.blogspot.com/


Автор: Гость (не зарегистрирован), дата: 23 сентября, 2020 - 17:06
#permalink

You have made some really good points there. I looked on the web to find out
more about the issue and found most individuals will go along with your views on this website
https://digitalseo24h.blogspot.com/


Автор: Гость (не зарегистрирован), дата: 23 сентября, 2020 - 17:13
#permalink

Fantastic blog! Do you have any helpful hints for aspiring writers?
I’m hoping to start my own site soon but I’m a little lost on everything.
https://sweetseo24h.blogspot.com/


Автор: Гость (не зарегистрирован), дата: 23 сентября, 2020 - 18:16
#permalink

I am hoping the same best effort from you in the future as well. In fact your creative writing skills has inspired me.
https://fancyseo24h.blogspot.com/


Автор: Гость (не зарегистрирован), дата: 29 сентября, 2020 - 16:25
#permalink

You have made some really good points there. I looked on the web to find out
more about the issue and found most individuals will go along with your views on this website
https://phoenixseogeek.com/


Автор: Гость (не зарегистрирован), дата: 1 октября, 2020 - 21:56
#permalink

Nice information, many thanks to the author. It is incomprehensible to me now, but in general, the usefulness and significance is overwhelming.
https://zgjskpzz1m.ga/


Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
5 + 6 =
Введите результат. Например, для 1+3, введите 4.
 
Текущий раздел
Поиск по сайту
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Последние комментарии
Последние темы на форуме
Forum