Последовательное сохранение настроек с использованием AJAX и очередей jQuery

    Добрый день, коллеги!

    В одном из проектов мне потребовалось сохранять выбранные пользователем настройки (сделанные в виде чекбоксов). Поскольку предполагалось, что настройки будут изменяться нечасто — я решил передавать настройки не все сразу, а в виде последовательности изменений. Детали реализации под катом.

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

    Можно сохранять просто асинхронными AJAX-запросами, но в этом случае может возникнуть не очень приятная ситуация, когда очередное изменение отправилось на сервер — и где-то по дороге застряло, а пользователь уже пытается сохранить контакт. В результате он получит не совсем то, что ожидал. Возникает вопрос — как сделать, чтобы изменения сохранялись строго по порядку. Для этого я решил воспользоваться имеющимися в jQuery очередями.

    Очереди в jQuery применяются для реализации анимации и эффектов, но никто не мешает использовать их просто для последовательного выполнения нужных действий. В результате у меня получился примерно такой код:

    function ajaxQueue(func){
        $(document).queue("ajax",func);
        if($(document).queue("ajax").length == 1)
            $(document).dequeue("ajax");
    }
    
    $(".contact input:checkbox")
        .change(function(){
            var $_ = $(this),
                checked = $_.is(":checked"),
            $_.attr("disabled","disabled");   
            ajaxQueue(function(){
                $.post("/ajax/check_elem",
                        {name: $_.attr("id"),
                        value: checked})
                .error(function(){
                    $_.val((!checked)?"on":"off"); 
                })
                .complete(function() {
                    $_.removeAttr("disabled");
                    $(document).dequeue("ajax");
                });
        });
    });
    


    При переключении чекбокса в очередь ставится новый шаг — функция отправки изменения на сервер. Если при этом очередь была пустая, то функция тут же запускается на выполнение (dequeue в функции ajaxQueue). После выполнения имеющегося в функции AJAX-запроса из очереди извлекается очередной шаг и выполняется.

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

    function doAction(link){
        $.get(link, function(data){
            $('body').append(data);
        }, 'html'); 
    }
    
    $("a.saveButton")
        .click(function(){
                ajaxQueue(doAction($(this).attr("href")));
        });
    


    PS: В процессе написания этой статьи я пришел к мысли, что все-таки проще передавать все состояния чекбоксов оптом перед сохранением контакта (это к вопросу о том, почему полезно писать статьи :) ), но возможно описанная мной схема кому-нибудь пригодится для других задач.
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 8

      +2
      Можно отправлять настройки на сервер с небольшим делеем, за время которого мы просто соберем все произошедшие изменения в один объект и отошлем его на сервер.
        +1
        а демку на jsfiddle.net не выложите?
        +1
        Новый запрос при каждом чеке/анчеке? Что с масштабируемостью? В статье самое ценное — P.S. )
          0
          Спасибо за статью.
          В принципе хорошее решение. Иногда именно нужно чтобы был правильный порядок запрос-ответ на сервер.
            0
            Статья цена именно как наглядный пример возможностей очередей jQ.
              0
              Вот если бы вы показали ajax-chain на основе очередей jquery, где можно выполнять, к примеру, последовательность вызовов к api vkontakte не чаще трех раз в секунду, то было бы очень клево. Пока очереди несколько притянуты за уши.
                +1
                Мне не довелось воспользоваться API vkontakte, но думаю, что минимально модифицировав приведенный код, можно сделать и последовательность вызовов не чаще 3 раз в секунду. Надо просто использовать вот такой вариант ajaxQueue:

                function ajaxQueue(func){
                    $(document).queue("ajax",function(){setTimeout(func, 333);});
                    if($(document).queue("ajax").length == 1)
                        $(document).dequeue("ajax");
                }
                

              Only users with full accounts can post comments. Log in, please.