Я собираюсь потратить много времени на решение проблемы, и мне интересно, есть ли существующий рецепт для этого.Это браузерное приложение (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?