вторник, 22 июня 2010 г.

Асинхронный вызов

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

Как же именно можно осуществлять подобные вызовы? Мне пришло в голову следующее шаманство:
Создадим объект, в который будем складывать последовательно функции, которые необходимо вызвать, а по завершению коллбэка вызывать на исполнение следующую функцию.
Что нам понадобится?
  • Массив, чтобы в нём хранить функции
  • Добавление функции в массив
  • Исполнение текущей функции
  • Индикатор, для того, чтобы понимать, когда-же закончился коллбэк.
У меня получилось вот такое прелестное чудо:
function SyncSequence(){
  this.__functions__ = new Array();
}
SyncSequence.prototype={  
  add:function(func){
    this.__functions__.push(func);    
  },
  wrapCallback:function(callback){
    var $this = this;    
    return function(){
      callback.apply(null,arguments);
      $this.runSequence();
    }
  },
  runSequence:function(){    
    if(this.__functions__.length > 0){
      this.__functions__.shift()();
    }
  }
}
В данном случае __functions__ является очередью, в который мы последовательно помещаем те вызовы, которые должны использовать.
wrapCallback создаёт функцию, которая заменит традиционный коллбэк. Основное её отличие заключается в том, что в конце исполнения данного ей коллбэка будет вызвана следующая функция в очереди.
Ну а runSequence просто запускает верхушку на исполнение. Процесс создания очереди будет выглядеть примерно так.
var ss = new SyncSequence();
ss.add(function(){
  test(1,ss.wrapCallback(testCallback))
});
ss.add(function(){
  test(2,ss.wrapCallback(testCallback))
});
ss.runSequence();
Конечно, не образец изящества, но всё-таки. Дополним код полусферическим примером:
function test(arg,callback){
  alert("Test started " + arg);
  setTimeout(function(){
    callback(arg + 100);
  },1000);
}

function testCallback(arg){
  alert("Test callback started " + arg);
}
При компоновке и запуске мне последовательно выдались 4 алерта:
  • Test started 1
  • Test callback started 101
  • Test started 2
  • Test callback started 102
Ура. Конструкция может существовать не только в невесомости, но и в условиях слабой гравитации. Поразительно, но мне для осуществления коварных планов по порабощению мира написанию одной маленькой утилиты этого богатства вполне хватило.
Будет нужно, подумаю что ещё можно будет добавить. А пока оставлю как есть.
И да, асинхронные вызовы снова стали синхронными. Троекратное ура.

Как всегда, исходные коды можно скачать.

1 комментарий: