У меня есть стандартный объект javascript, прототип которого расширен методом .start()
, принимающим в качестве аргументов 2 обратных вызова: success
и failure
соответственно. Этот метод выполняет некоторую асинхронную обработку (это не AJAX) и в зависимости от результата этой обработки вызывает либо обратный вызов успеха, либо обратный вызов неудачи.
Вот как это можно схематизировать:
function MyObject() {
}
MyObject.prototype.start = function(successCallback, errorCallback) {
(function(s, e) {
window.setTimeout(function() {
if (Math.random() < 0.8) {
s();
} else {
e();
}
}, 2000);
})(successCallback, errorCallback);
}
Не так уж важна точная обработка, выполняемая внутри метода, важно только то, что она асинхронная и неблокирующая. Я не могу контролировать момент времени, когда метод start завершит обработку. Я также не контролирую прототип и реализацию этого метода.
Что я могу контролировать, так это обратные вызовы success
и failure
. Их предоставление зависит от меня.
Теперь у меня есть массив этих объектов:
var arr = [ new MyObject(), new MyObject(), new MyObject() ];
Порядок элементов в этом массиве важен. Мне нужно, чтобы метод .start()
срабатывал последовательно на каждом элементе массива, но только после того, как завершится предыдущий (т.е. будет вызван обратный вызов успеха). А если произойдет ошибка (будет вызван обратный вызов неудачи), я хочу остановить выполнение и больше не вызывать метод .start на оставшихся элементах массива.
Я мог бы реализовать это наивно, используя рекурсивную функцию:
function doProcessing(array, index) {
array[index++].start(function() {
console.log('finished processing the ' + index + ' element');
if (index < array.length) {
doProcessing(array, index);
}
}, function() {
console.log('some error ocurred');
});
}
doProcessing(arr, 0);
Это работает хорошо, но глядя на jQuery's deferred Object, который был представлен в jQuery 1.5, я думаю, что есть место для улучшения этого кода. К сожалению, я пока не чувствую себя очень комфортно с ним и пытаюсь его изучить.
Так что мой вопрос, возможно ли адаптировать мой наивный код и воспользоваться преимуществами этого нового API, и если да, не могли бы вы дать мне несколько указателей?
Вот jsfiddle с моей реализацией.