Нужен рецепт: множественные асинхронные запросы Ajax в JavaScript - PullRequest
2 голосов
/ 13 сентября 2010

Я собираюсь потратить много времени на решение проблемы, и мне интересно, есть ли существующий рецепт для этого.Это браузерное приложение (JavaScript и Dojo Toolkit), являющееся клиентом веб-службы RESTful.

Оно использует Comet для автоматического обновления дисплея.Существует функция обратного вызова, которая обрабатывает каждое полученное сообщение.[Скучные детали Comet: в качестве некой фоновой операции на сервер отправляется HTTP-запрос.Этот запрос блокируется на сервере, пока не получит сообщение для нас.Когда клиент наконец получает ответ, он вызывает функцию обратного вызова и затем выполняет следующий HTTP-запрос.HTTP допускает до двух одновременных запросов, поэтому этот «фоновый» запрос не блокирует «приоритетные» запросы, которые происходят, когда пользователь что-то делает.]

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

var ourEventFilter = dojo.hitch(this, function(evt) {
  if (evt["obj"]) {
        evt.obj = this.transform(evt.obj);
  }
  callUIEventHandler(evt);
}

[dojo.hitch () - синтаксический сахар для замыкания, связывающий функцию this.]

obj может выглядеть примерно так:

{
   "resources": [
      {"name":"Me", "type":"vm", "link":"http://server/item/ABC"},
      {"name":"You", "type":"real", "link":"http://server/item/123"}],
   "subObjs": [
      "resources":[{"name":"Him", "type":"vm", "link":"http://server/item/DEF"} 
   ]
}

Функция преобразования превращает его в следующее:

{
   "resources": [
      {"name":"You", "type":"real", "link":"http://server/item/123"},
  ],
   "vms": [
      {"name":"Me", "type":"vm", "link":"http://server/item/ABC"}],
   "subObjs:" [
      "resources":[],
      "vms": [{"name":"Him","type":"vm", "link":"http://server/item/DEF"}]
   ]
}

Мы находим те «ресурсы» типа «vm» и перемещаем их в отдельный массив.Все идет нормально.Функция преобразования достаточно проста.Это рекурсивно, потому что subOjbs может содержать subObjs.

Но теперь нам нужно больше информации о vms.Нам нужно сделать Ajax-вызовы на сервер, чтобы получить эту информацию:

{
   "resources": [
      {"name":"You", "type":"real", "link":"http://server/item/123"}],
   "vms": [
      {"name":"Me", "type":"vm", "link":"http://server/item/ABC", "moreInfo":"X"}],
   "subObjs:" [
      "resources":[],
      "vms": [{"name":"Him","type":"vm", "link":"http://server/item/DEF", 
                "moreInfo":"Y"}]
   ]
}

Функция преобразования выглядит примерно так:

transform: function(obj) {
      var vms=[];
      var newResources = [];
      // Recurse on subObjs
      if (obj.subObjs) {
         for (var kx = 0; kx < obj.subObjs.length; kx++) {
            ojb.subObjs[kx] = this.transform(obj.subObjs[kx]);
      }
      // Move vms out of resources into vms
      if (obj.resources) {
         for (var jx = 0; jx < obj.resources.length; jx++) {
            if (obj.resources[jx].type == "vm") {
               var thisVM = obj.resources[jx];
               // Note:  more info needed here.
               //thisVM = this.getMoreInfo(thisVM);
               vms.push(thisVM);
            } else { 
               newResources.push(obj.resources[jx];
            }
         }
         obj.vms = vms;
         obj.resources = newResources;
      }
      return obj;
}

И теперь у нас есть проблема.Как мне написать getMoreInfo ()?

Я мог бы сделать синхронные вызовы на этом этапе:

getMoreInfo: function(vm) {
   vmObj = callServerSynchronouslyToGET(vm.link);
   vm.moreInfo = vmObj ? vmObj.moreInfo : null;
}

Но синхронные вызовы никогда не являются хорошей идеей в Ajax (это будет Sjax).

Я не думаю, что можно написать getMoreInfo () как таковую для выполнения асинхронных вызовов.Я должен вернуться через несколько слоев лука и переписать все с определенной точки вниз, надеюсь, не переписывая ничего выше слоя обратного вызова Comet.

Я знаю рецепт, который преобразует рекурсивную функцию внерекурсивная функция.Есть ли рецепт, который превращает лук с циклом с синхронным GET в центре в цепочку асинхронных GET?

1 Ответ

1 голос
/ 23 сентября 2010

Существует кросс-браузерное расширение для языка JavaScript, которое называется StratifiedJS.

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

Библиотека JS, которая включает StratifiedJS в браузере, называется "Oni Apollo". Подробнее см. http://onilabs.com/apollo.

В вашем конкретном случае вы можете преобразовать весь свой асинхронный лук в синхронный код, используя StratifiedJS, или вы можете сохранить существующую логику, просто вставив ее в элемент сценария "text / sjs":

<script src="http://code.onilabs.com/latest/oni-apollo.js"></script>

<script type="text/sjs">

  // your existing code here

  getMoreInfo: function(vm) {
    var vmObj = require('http').get(vm.link);
    vm.moreInfo = vmObj ? vmObj.moreInfo : null;
  }
</script>

Здесь require ('http'). Get () выполняет асинхронный XHR под капотом (подробности см. В документации apollo api по ссылке выше).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...