понедельник, 22 сентября 2014 г.

Шаблон Deferred Object

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


Описание проблемы


Вообще, подобные задачи на практике встречаются нечасто. Я столкнулся с ней при работе с API vk.com, когда мне нужно было получить посты из нескольких публичных страниц, потом их все вместе как-то обработать и показать некоторую выборку.

Вызов метода API выглядит примерно так:

VK.Api.call('wall.get', params, callback);

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

Решение


Я понимал, что наверняка для этой проблемы существует решающий ее шаблон. Так и оказалось, этот шаблон - Deferred Object. По сути, deferred object просто хранит состояние асинхронной функции. Их может быть три:
  • pending, т.е. ожидание завершения
  • rejected, т.е. выполнение завершено неудачно
  • resolved, т.е. выполнено успешно

Таким образом, чтобы использовать этот шаблон, мы должны создать Deferred object, передать его туда, где его состояние будет отслеживаться, а когда асинхронная функция будет выполнена, перевести его из состояния pending в состояние resolved или rejected.

В jQuery уже есть своя реализация Deferred Object - $.Deferred. Можно ей и воспользоваться. Я положу все состояния асинхронных запросов в одну коллекцию и дождусь, когда все они перейдут в resolved.

var def, 
    posts = [],
    deferred = [];

for (var i = 0; i < publics.length; ++i) {
   def = (function(params) {
      var defObj = new $.Deferred();

      VK.Api.call('wall.get', params, function(r) {
         if (r != undefined && r.response != undefined) {
            posts.push(r.response);
         }

         defObj.resolve();
      });

      return defObj.promise();
   })(publics[i].params);

   deferred.push(def);
}

$.when.apply($, deferred).done(function() {
   // processing ...
});

Код немного подправлен для наглядности. Объясню, что произошло. Перед отправкой каждого асинхронного запроса, я создаю Deferred Object, который переводится в состояние Resolved только когда приходит ответ. Все созданные объекты помещаются в общий массив, который потом передается функции $.when, где происходит ожидание, пока все deferred objects не перейдут в состояние Resolved.

Стоит обратить внимание на то, что в массив deferred попадают не сами $.Deferred, а Promised-версия Deferred Object. По сути, это просто "урезанная" копия Deferred Object, которая не позволяет изменить свое состояние вызовом у нее специального метода.

Для вызова функции $.when, я использовал Function.prototype.apply, которая переводит переданный массив объектов в список аргументов, т.к. в документации $.when описан как метод, принимающий список параметров, а не массив.

Ссылки


3 комментария:

  1. Non-fungible tokens, or NFTs, are digital certificates of authenticity attached to photographs, artwork or other belongings that prove possession of the asset. This web site is using a safety service to guard itself from online attacks. There are several of} actions that might set off this block together with submitting a certain word or phrase, a SQL command or malformed data. That is far from the excellent analysis required to understand on line casino 소울카지노 payouts actually.

    ОтветитьУдалить
  2. There should not be any concern about dropping your cash at a UK on line casino that is licensed. So that you do not lose your cash if anything occurs to the on line casino, it is best to keep the funds separate. The most important consideration when considering whether you need to sign up for|to 카지노사이트 join|to enroll in} an uk best on line casino sitesis security and licensing. Most of the 21 players wished to stay anonymous, as they were ashamed of their addictions and didn't need their family members to find out|to search out} out about their habits. But that has not stopped Shellz and her husband from spending about $150,000 within the game in simply two years. She requested to use her in-game username so her family doesn't find out how a lot cash they have spent on the game.

    ОтветитьУдалить
  3. The authorized 1xbet distinction between a "name wager" and an "introduced wager" is that a "name wager" is a wager known as by the participant with out him putting any cash on the table to cowl value of|the price of} the wager. In many jurisdictions this is thought-about gambling on credit and towards the law|is unlawful}. This is the definitive model of online roulette with a single zero together with numbers 1 to 36.

    ОтветитьУдалить