давайте все же расмотрим конкретный пример: ресайз картинок на клиенте с помощью flash.
Например, есть форма изменения юзерпика, в которой пользователь выбирает изображение. В результате появляется диалоговое окно, в котором пользователь указывает, как надо обрезать это изображение. Нажимает "Ok" диалогового окна, потом кнопку "Сохранить" формы. Получается что-то типа:
var chain = new AsyncChain();
$('jsChangeUserpicForm-eUserpicField').addEvent('change', // input type="file"
chain
.setOptions({
onFailure: function() {
// показать пользователю сообщение об ошибке
this.fireEvent('complete');
},
onComplete: function() {
new Button('jsChangeUserpicForm-eAttachFileLink')
.enable();
$('jsChangeUserpicForm-eAttachFileThrobber')
.addClass('sInvisible');
this.state('cropResizeUserpicDialog')
&& this.state('cropResizeUserpicDialog').close();
}
})
.add(function() {
new Button('jsChangeUserpicForm-eAttachFileLink')
.disable();
$('jsChangeUserpicForm-eAttachFileThrobber')
.removeClass('sInvisible');
})
.add(function(NEXT) {
sendForm({
form: 'jsChangeUserpicForm',
url: '/upload/userpic',
onSuccess: function(userpicURL) {
chain.state('userpicURL', userpicURL);
NEXT();
},
onFailure: function() {
chain.fireEvent('failure');
}
});
})
.add(function(NEXT) {
this.state('cropResizeUserpicDialog', new CropResizeUserpicDialog({
userpicURL: chain.state('userpicURL'),
dstWidth: 100,
dstHeight: 100,
onOk: function(cropX, cropY, cropWidth, cropHeight, resizeWidth,
resizeHeight) {
this.state({
cropX: cropX,
cropY: cropY,
cropWidth: cropWidth,
cropHeight: cropHeight,
resizeWidth: resizeWidth,
resizeHeight: resizeHeight
});
NEXT();
},
onCancel: function() {
chain.fireEvent('complete');
}
}));
})
.add(function() {
this.state('cropResize', new CropResize());
this.state('cropResize').load(this.state('userpicURL'), {
onSuccess: function() {
NEXT();
},
onFailure: function() {
chain.fireEvent('failure');
}
});
})
.add(function() {
this.state('cropResize')
.crop(
this.state('cropX'),
this.state('cropY'),
this.state('cropWidth'),
this.state('cropHeight')
)
.resize(
this.state('resizeWidth'), this.state('resizeHeight'),
)
.save({
url: '/upload/thumb',
onSuccess: function() {
NEXT();
},
onFailure: function() {
chain.fireEvent('failure');
}
});
})
.add(function() {
if ($('jsChangeUserpicForm-eUserpicURLField')) {
var eUserpicURLField = $('jsChangeUserpicForm-eUserpicURLField');
} else {
var eUserpicURLField = new Element({
id: 'jsChangeUserpicForm-eUserpicField',
type: 'hidden'
});
eUserpicURLField.inject('jsChangeUserpicForm');
}
eUserpicURLField.name = 'userpic-url';
eUserpicURLField.value = this.state('userpicURL');
$('jsChangeUserpicForm-eUserpicThumb').src = this.state('userpicURL');
});
);
дополнительные преимущества:
1) возможность научить addEvent запускать цепочки в ответ на событие;
2) предоставление интерфейса для работы с состоянием позволяет повторно использовать цепочку - для этого надо перед запуском цепочки очистить состояние; если пользователь сам придумывает, где хранить состояние, нету возможности его очистить;
3) возможность организовать аналогию блока finally из try-catch (событие complete).
p.s. это я называю конкретным примером. Наличие кода необязательно в общем-то, но в твоем примере с гипотетическим парсером непонятно даже какие действия составляют цепочку, не говоря уже о данных, составляющих состояние цепочки. Т.е. не хватает важной информации.