История старая, я так думаю, все помнят window.cookie = '...' (а может кто этим пользуется), жутко неудобная штука.

Приведу пример на нативном js:

// Добавление печенья
function setCookie(key, value) {
  window.cookie = key + '=' + encodeURIComponent(JSON.stringify(value));
}

// Получение печенья
function getCookie(key) {
  var matches = document.cookie.match(new RegExp(
    '(?:^|; )' + key.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + '=([^;]*)'
  ));
  return JSON.parse(decodeURIComponent(matches[1]));
}

// Добавляем строку
setCookie('string', 'Моя строка');
// Добавляю объект
setCookie('object', {a: 1, b: 2});

// Получаю объект
var object = getCookie('object');


Давным-давно в закаулках сети я нашёл такую замечательнуюи вещь как jQuery cookie, но со временем я стал осознавать, что одного метода мне уже не хватает для удобной работы с печеньем.

Тот же пример с jQuery cookie:

// Добавляем строку
$.cookie('string', 'Моя строка');
// Добавляю объект
$.cookie('object', {a: 1, b: 2});

// Получаю объект
var object = $.cookie('object');

Совсем не давно я стал знакомиться с angular, и как не странно у них тоже своя реализация cookies, не много лучше, но мне она кажется немного «странной», «мудрёной». Методы putObject, getObject — вообще ужас, и зачем они?

И опять пример:

angular.module('cookiesExample', ['ngCookies'])
.controller('ExampleController', ['$cookies', function($cookies) {
  // Добавляем строку
  $cookies.put('string', 'Моя строка');
  // Добавляю объект
  $cookies.putObject('object', {a: 1, b: 2});

  // Получаю объект
  var object = $cookies.getObject('object');
}]);

Мне надоело это разнообразие красок, хотелось бы чего нибудь одного такого теплого, уютного что бы выполняло самые простые вещи и давало отличные инструменты для работы с cookie. Я ушёл глубоко в поиск и к моему удивлению я не чего подходящего мне не нашёл, в не которые библиотеках не хватало методов, в других методов достаточно но они странные для меня. Может я слишком придирчив?

На почве этого всего я решил изобрести свой велосипед с максимально круглыми колёсами и удобным сидением. Мне кажется это правильно. Работа затянулась на несколько суток, в общем вот что получилось сама библиотека tasty-cookies ну и русская документация.

Пример работы tasty-cookies:

Cookie.set({
  // Добавляем строку
  string: 'Моя строка',
  // Добавляю объект
  object: {a: 1, b: 2}
});

// Получаю объект
var object = Cookie.get('object');

Она использует объект JSON поэтому если надо поддержка старых браузеров можно подтянуть грабли типо JSON 3, хотя, о чем это я?

Хотелось бы услышать критики, оценки работы, ну и само собой предложений по улучшению библиотеки.

Комментарии (36)


  1. greabock
    05.04.2016 16:32
    +9

    Эм… в свете того факта, что повсеместно насаждается идея server-only кук, а для хранения локальной информации, лучше всё-таки использовать, (простите за тавтологию) Local Storage, хочется лишь добавить картинку с тролейбусом… но лень искать ссылку.


    1. Alex5646
      05.04.2016 18:00
      +2

      Web Storage API Плохо телефонами поддерживается, а opera mini так вообще не знает что это такое а только она занимает 30% доли рынка. Это подходит для конкретного проекта и задачи. Пока к сожалению этим нельзя полностью заменить cookies.

      Как быть если проект заточен под телефоны?

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


      1. uSide
        05.04.2016 18:42
        +1

        по словам caniuse, оперой пользуются ~5%

        image


        1. Alex5646
          05.04.2016 19:05
          +2

          Ну тоже ведь люди.

          Думаю реализовать возможность выбора метода сохранения печенья, там LocalStorage, SessionStorage и Cookie, ну для первых это получиться просто синтаксическая обёртка позволяющая добавлять и получать данные массивами.

          К примеру:

          // Ставим 4 печенек
          Cookie.set({
            a: 1,
            b: 2,
            c: 3,
            d: 4
          });
          
          // Получаем две печеньки
          Cookie.get('a', 'b'); // -> {a: 1, b: 2}
          
          // Удаляю три печеньки
          Cookie.remove('a', 'b', 'c');
          


          1. jMas
            05.04.2016 20:11
            +1

            Тогда лучше перестать называть это Cookie, потому что это вводит людей в заблуждение. Например, человек сохраняет информацию через обертку называемую Cookie, смотрит в отладочную консоль на куки — а там пусто.


            1. Alex5646
              05.04.2016 20:18

              Сделаю объект, и создам три экземпляра Cookie, Local и Session. И тут из названия думаю понятно что и где хранит данные.


              1. jMas
                05.04.2016 23:36

                Лучше создать обертку под названием ClientStorage, в настройках которой можно указать в какие хранилища можно дублировать информацию.

                Это не самый лучший пример программирования, но все же
                ClientStorage.setup({
                useCookies: true,
                useLocalStorage: true,
                useSession: true
                });
                ClientStorage.set({
                  a: 1,
                  b: 2,
                  c: 3,
                  d: 4
                });
                ClientStorage.get('a', 'b'); // -> {a: 1, b: 2}
                ClientStorage.remove('a', 'b', 'c');
                


                1. denis_g
                  06.04.2016 10:28

                  A еще можно использовать какой-нибудь polyfill.

                  P.S. Кстати, это я слоупок или Markdown для комментариев появился только что?


    1. rumkin
      06.04.2016 13:37

      Мне в проекте нужны именно куки для хранения данных, которые должны автоматически удалиться через определенное время и localStorage мне, ну, никак в этом не поможет.


      1. Nadoedalo
        06.04.2016 15:44

        ага, поэтому зачем нам проверять чё мы там храним, давайте посылать всё г**но на сервер.
        Метку времени к записываемым данным добавить сложно что-ли? Куки всёравно удаляются только тогда когда происходит их запрос. Так же поступать и с LS.


        1. rumkin
          06.04.2016 16:28
          -2

          Для не особо понятливых: еще раз прочтите мой комментарий и обратите внимание на слово автоматически.


          1. TheShock
            06.04.2016 22:13

            О боги! Сложность написания автоматического удаления данных просто бесконечно велика!


            1. rumkin
              07.04.2016 01:01
              -2

              Да, вы должно быть шутите!? Давайте еще раз АВТОМАТИЧЕСКИ! Подумайте, а потом я объясню, что означает это слово, если и в этот раз не прокатит.


              1. kazmiruk
                07.04.2016 10:18
                -1

                Тогда замените слово АВТОМАТИЧЕСКИ на НО МНЕ ЛЕНЬ ПИСАТЬ КОД, так как написанная Вами чистилка кукисов по времени будет тоже автоматизацией. Не автоматически это когда заходишь и ручками начинаешь удалять.


                1. rumkin
                  07.04.2016 14:29
                  -1

                  Это не мне лень писать код, это вам лень думать!
                  Если выключить скрипты, то данные из LS не удалятся. Если же вы поместите данные в cookie, то они удалятся даже с выключенными скриптами, т. е. автоматически. И да, без необходимости писать дополнительный код.


                  1. Nadoedalo
                    07.04.2016 15:51

                    т.е вы храните данные в куках, которые использует сервер для бизнес-логики? Да вы должно быть шутите.
                    Тут два варианта — либо сообщение не имеет ничего общего с библиотекой для работы с куки, либо данные и не появятся в куках из-за выключенного JS.
                    PS куки никуда не денутся пока браузер не попытается их отправить. Я, конечно, могу ошибаться но ВСЕ манипуляции с куками происходят ИСКЛЮЧИТЕЛЬНО при запросах на сервер в домене. Браузер не будет перепроверять 100500 кук каждый раз когда запускается.


                    1. rumkin
                      07.04.2016 19:53

                      В данном случае не имеет значения, что хранится в куках, важно, что данные удаляются по истечению таймера и становятся не доступными вне зависимости от того включен JS или нет в момент загрузки страницы.


                      1. Nadoedalo
                        07.04.2016 20:23
                        +1

                        Данные в куках не удалятся если, например, не запускать браузер. Напишите куку с экспайром в 1970 году, закройте браузер и зайдите в папку с куками. Ваши данные будут там.
                        Если выключен JS — данных по сути нет. Включён JS — удалится по метке времени.

                        Преимуществ у куки по сравнению с LS нет, особенно в сфере хранения ДАННЫХ. Нормальные приложения хранят в куках идентификаторы, а данные — на сервере. И вот на сервере уже точно можно следить за удалением данных.

                        Единственный минус решения на LS очень прост — нужно будет написать буквально с десяток строчек кода сверху кода гетеров/сетеров/добавляторов(и заметьте, не надо никаких либ)

                        Зато плюсов от нормального решения на localStorage — мильён.


                        1. rumkin
                          08.04.2016 11:42
                          -1

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


                          Короче, когда мне понадобится решение с LS, я буду использовать LS. Вы же мне пытаетесь впарить кейс, который мне не нужен. А нужно было то, что я уже описал выше. Как и для чего я это использую – флейм за рамками дискуссии.


                          Всего доброго.


  1. o_nix
    05.04.2016 17:12
    -1

    Печенье! Печенье, Карл!..


  1. Akuma
    05.04.2016 18:06
    +2

    А вот я вас поддержу. Хотя и редко куки на клиенте нужны, но все же, спасибо, у вас поудобнее чем аналоги (Ангуляр вообще ужасно все реализовал, как ни странно)

    Только один вопрос, зачем, ну зачем вам интеграция с jQuery? ))) Я понимаю, что это две с половиной строки, но просто… зачем?)) Ведь не будет никакой совсем разницы, что с ним, что без него.

    А за пакет в npm отдельное спасибо, привык уже все через него ставить.


    1. Alex5646
      05.04.2016 18:54
      -1

      ну зачем вам интеграция с jQuery
      Просто как синтаксическая обёртка. Где то подсмотрел, наверное все таки излишнее.


      1. Akuma
        05.04.2016 18:55
        +1

        Лучше наверное убрать. Создает впечатление зависимости от jQuery.


        1. Alex5646
          05.04.2016 19:08
          -1

          Сейчас так и сделаю.


  1. TheShock
    05.04.2016 19:49
    +9

    Как на меня — вы опоздали с этой либой лет на 15. Оно уже было в MooTools, dojo, atomjs и так далее. Я уж молчу про кучи независимых маленьких библиотечек и плагинов для всяких undescore. И это годы назад.


    1. Evgeny42
      06.04.2016 01:11
      +1

      А так же куча библиотек, которые поддерживают множественные варианты для хранения, выбирая лучшее из доступного.


  1. kazmiruk
    06.04.2016 11:59

    Если я не ошибаюсь, то в IE будет работать неверно. Если у Вас есть домен example.com и sub.example.com, Вы создаете на каждом домене по куке my_cookie с разными значениями без указания домена (https://tools.ietf.org/html/rfc6265#section-4.1.2.3), т.е. кука не будет проваливаться на сабдомены. Но IE не совсем нормальный браузер. Он отдаст обе куки для сабдомена и когда Вы будете брать первое совпадение по регулярке — будете получать куку с example.com, а не с sub.example.com, как ожидалось, потому что:

    «Q3: If I don’t specify a DOMAIN attribute when a cookie, IE sends it to all nested subdomains anyway?

    A: Yes, a cookie set on example.com will be sent to sub2.sub1.example.com.

    Internet Explorer differs from other browsers in this regard. Here’s a test case (http://debugtheweb.com/test/cookieinherit.aspx)»


    1. Alex5646
      06.04.2016 12:17

      Да действительно так. Надо добавить проверку домена.


      1. kazmiruk
        06.04.2016 12:33

        Проверка домена не прокатит, так как на уровне js (как и на сервере, в принципе) невозможно получить атрибут domain куки. Или я чего-то не знаю и есть какой-то способ (не мастер js, если честно)?


  1. adoconnection
    06.04.2016 21:50
    -2

    Веселье начнется, когда неймспейс Cookie от tasty-cookies пересечётся с неймспеском Cookie от другой библиотеки :)


    1. Alex5646
      06.04.2016 21:51
      +1

      А что вы предлагаете? Кто вообще две библиотеки для одного и того же подключает?


      1. adoconnection
        07.04.2016 12:52

        > Кто вообще две библиотеки для одного и того же подключает?
        первый разработчик сделает крутую библиотеку А использовав tasty-cookies,
        второй разработчик сделает крутую библиотеку Б использовав другую Cookie-библиотеку с таким же именем Cookie.
        третий – захочет одновременно использовать А и Б и получит конфликт.

        Классический пример – Array.prototype.select или forEach во времена, когда jquery был еще не в ходу, а подобие лямбда выражениям в JS уже хотелось. Кажется, каждый пилил свою реализацию, а уже в производных библиотеках происходили конфликты. Сам с этим сталкивался, это очень больно.

        > А что вы предлагаете?
        Лично я бы хранил эти функции внутри фреймворка без глобального объекта. А если бы очень хотелось глобальный объект, то, хотя бы, назвал бы его по другому, исключив банальные конфликты с именами кучи уже сделанных решений Cookie / Cookies.


        1. Alex5646
          07.04.2016 13:31

          По поводу перового говорить не буду, покажу пример:

          <script src="path/tasty-cookies.js"></script>
          <script src="path/library-a.js"></script>
          <script>
          var tastyCookies = Cookie;
          delete Cookie;
          </script>
          <script src="path/cookies2.js"></script>
          <script src="path/library-b.js"></script>
          

          Хотя с такой не согласованностью разработчиков, конкретная фигня получается. Эдакий сниппет стайл. Не советую так делать.

          Вам вообще известно что такое модули? Модульный подход эти проблемы решает на раз два.
          Пример 2:
          // libaryA.js
          exports.libaryA = (function (){
             var cookies = require('tasty-cookies');
          }());
          
          // libaryB.js
          exports.libaryB = (function (){
             var cookies = require('cookies2');
          }());
          
          // core.js
          exports.core= (function (){
             var libraryA = require('libraryA');
             var libraryB = require('libraryB');
          }());
          

          Я здесь не вижу проблем. А чтобы это юзать в браузере придан давно browserify.

          Классический пример
          Классический пример плохого js. Кто же стандартные объекты трогает, здесь глюков не избежать. Уже давно придуманы классы, пространства имён и модули.

          По поводу третьего, я могу подтянуть 5 фреймворков засоряющих одно пространство имён. И как тут быть?


          1. Alex5646
            07.04.2016 13:38

            Извиняюсь не правильно прописал подключение tasty-cookies. Не могу редактировать, кому интересно можно посмотреть здесь как правильно подключается github.com/Alex5646/cookie.js#use-in-commonjsnode


            1. adoconnection
              07.04.2016 15:00

              Вместо попыток меня уделать, попробуйте понять суть проблемы :)

              Но раз уж дошло до срача, и вы просили критики в статье, вот вам критика:

              1. во первых вы хреново прогуглилили github.com/js-cookie/js-cookie (с 2009 года)
              На вскидку – 1 в 1 с вашим велосипедом. Они, кстати, подумали о возможном конфликте неймспейсов, лохи, модулями то не умеют пользоваться :)

              2. Вот 302 репозитория на эту или похожую тему
              github.com/search?l=JavaScript&q=js+cookie&type=Repositories&utf8=%E2%9C%93
              уже на второй странице некий jonlabelle использует такой же неймспейс github.com/jonlabelle/cookie-js
              и кажется делает все то же самое, но наверняка есть нюансы.
              Одному Богу известно сколько людей и как используют этот код, созданный еще в 2012 году. Может быть он встретится в очередном попсовом лайтбоксе, или в няшненьком jquery плагине, который, так получилось, написан без изысков, но уже сейчас очень нужно им использовать, чтобы не писать с нуля.

              И когда кучи плагинов и библиотек начинают тянуть за собой всякие Cookie, Linq, Strings и Dates, то, иногда, (конечно не всегда) начинается жопа. Например, когда ваше громадное решение встраивается в страницу как API в чужое огромное решение.
              То что вы не видите в этом проблемы не значит, что этой проблемы нет. Технический долг есть всегда и он даст о себе знать.

              Вопрос по 5 фреймворкам адресуйте их создателям.

              Не просите критики, если не готовы к ней.


              1. Alex5646
                07.04.2016 19:01
                +1

                Ни одна из приведённых библиотек не может задать куки массивом, также удалять сразу несколько кук и получать. Также нет возможности получить все ключи, все куки. А метод clear реализован только у последнего. Из поиска могу выделить только несколько библиотек к сожалению.

                Кстати код js-cookie метода noConflict прям в точь в точь из моего первого примера, только есть одно маленькое но они не освобождают пространство имён (Не удаляют переменную), а тупо создают клон мол сами удаляйте или перебивайте.

                Пожалуй напишу метод noConflict. Ещё гетер length запилю, думаю пригодиться.