В текущем проекте возникла необходимость выполнить последовательную серию ajax запросов и, по завершении — что-то сделать со всеми их результатами. Довольно типовая задача, паттерн ее решения обычно называют waterfall (водопад). Реализации этого паттерна есть для node.js, хотя некоторые работают и в браузере — async.
Но включать целый модуль ради одного метода не хотелось. Copy/paste тоже не стал делать, но по соображениям скорее эстетическим. В async в метод передается функция обратного вызова, у нас же везде используется jQuery.Deferred. Разницы, конечно, никакой, но «ломать» стиль проекта мое «чувство прекрасного» мне не позволило :)
В результате написал небольшую утилитку по аналогии с jQuery.when
В отличии от jQuery.when аргументами надо передавать не jqxhr, а функции, их возвращающие, иначе теряется смысл водопада. Хотя ошибки это не вызовет, поскольку waterfall принимает любые типы аргументов.
Использовать ее просто.
1. Выполним по очереди 3 запроса и покажем результаты:
$.waterfall( function() { return $.ajax(...) }, function(arg1) { return $.ajax(...) }, function(arg2) { return $.ajax(...) } ) .fail(function(error) { console.log('fail'); console.log(error); }) .done(function() { console.log('success'); console.log(arguments); })
2. Выполним один запрос, проверим, что он вернул и решим, что делать дальше:
$.waterfall( function() { return $.ajax(...) }, function(arg1) { return arg1 && arg1.answer == 42 ? $.ajax(...) : false; }, function(arg2) { return $.ajax(...) } ) .fail(function(error) { console.log('fail'); console.log(error) }) .done(function() { console.log('success'); console.log(arguments) })
3. waterfall может принимать любые типы аргументов. false немедленно прервет водопад, остальные значения отличные от функций и deferred объектов будут просто добавлены в результат:
var dfrd = $.Deferred(); $.waterfall( function() { return $.ajax(...) }, $.ajax(...), // будет выполнен "вне очереди" dfrd, // серия не закончится пока вручную не сделаем resolve/reject 'string', 42, false // серия всегда завершится ошибкой ) .fail(function(error) { console.log('fail'); console.log(error) }) .done(function() { console.log('success'); console.log(arguments) })
Вот, собственно, и все. Критика и советы приветствуются.
Код на гитхабе
