Начало
Само существование Common JS Promises мне было известно давно. К взаимному проникновению меня толкнул Angular.js, который имеет свою реализацию promise/deferred. Немного помучившись с реализацией тех самых цепочек на основе promises, стало понятно, что promises для этого и не предназначены. Поэтому было принято решение изобрести велосипед пойти дальше и сделать необходимую функциональность самому.
К делу
В ходе размышлений о программном интерфейсе, Сhain.js обзавелась списком из 5 функций: 1 конструктор и 4 метода. Сжатая реализация имеет размер в 2.03КБ, полная (без комментариев ^_^) реализация имеет размер в 3.15КБ. Скачать эти файлы можно на странице сделанной специально для Chain.js. Прямых ссылок нет, боюсь, могу сломать.
Установка тривиальна, не отличается от других скриптов.
<script src="js/chain.dev.js" type="text/javascript"></script>
После этого библиотека доступна в глобальной области видимости (
window
, видимо) под именем Chain
. Chain
является конструктором новой цепи и имеет два основных варианта вызова (дополнительные варианты можете придумать сами):var testChain = Chain();
// или
var anotherChain = new Chain;
Теперь мы можем ощутить всю мощь создавать наши цепи, для этого у нас есть 3 метода:
.then(Function | Array.<Function>)
.defer(Function | Array.<Function>)
.when(Chain | Array.<Chain>)
Метод
.then
принимает синхронные функции, .defer
— асинхронные, .when
— объекты Chain
. Все 3 метода возвращают объект Chain
, для которого вызываются (прямо как jQuery chaining). Также эти методы могут принимать либо один требуемый аргумент, либо массив таких аргументов. Для методов .then
и .defer
результат выполнения предыдущего звена передается следующему в указанную функцию первым аргументом.Выполняется цепь только тогда, когда будет вызван метод
.end
, он же последний метод библиотеки.Имеет такую сигнатурку:
- .end([Function])
Функция будет вызвана при завершении всех операций в цепи. Указание функции необязательно.
Примеры для понимания:
var calculate = Chain();
calculate.
then(function() { // первая функция вызывается с аргументом undefined
return 0;
}).
then(function(result) { // не трудно догадаться, result равен 0
return result + 5;
}).
then(function(result) { // result равен 5
return result + 10;
}).
end(function(result) { console.log(result); }); // выведет 15
Иная запись с тем же результатом:
var calculate = new Chain;
function zero() { return 0; }
function plus5(num) { return num + 5; }
function plus10(num) { return num + 10; }
function log(result) { console.log(result); }
calculate.
then([zero, plus5, plus10]).
end(log); // выведет 15
Проделаем тоже самое асинхронно:
var calculate = Chain();
calculate.
defer(function(n, done) {
// первый аргумент будет равен undefined,
// второй - функция, которую надо вызвать при завершении нашей операции
done(0);
}).
defer(function(result, done) { // result равен 0
// та самая асинхронность
setTimeout(function() {
done(result + 5);
}, 1000);
}).
defer(function(result, done) { // result равен 5
done(result + 10);
}).
end(function(result) { console.log(result); }); // выведет 15
Тоже самое, по-другому:
var calculate = new Chain;
function zero(n, done) { done(0); }
function plus5(num, done) {
setTimeout(function() {
done(num + 5);
}, 1000);
}
function plus10(num, done) { done(num + 10); }
function log(result) { console.log(result); }
calculate.
defer([zero, plus5, plus10]).
end(log); // выведет 15
Ну и наконец, метод
.when
служит для соединения остальных ваших цепей. После выполнения метода .when
в следующее звено передается массив с результатом выполнения предыдущих звеньев-цепей. Пример:var five = Chain(), ten = Chain();
five.defer(function(n, done) {
setTimeout(function() {
done(5);
}, 1000);
});
ten.
when(five).
then(function(results) { return results[0] + 5; }); // results будет равен [5]
Chain().
when([ten, five, ten]).
end(function(results) { console.log(results); }); // выведет [10, 5, 10]
Особенности работы
Цепи переданные в метод
.when
выполняются параллельно. Последовательность в результирующем массиве будет соответствовать последовательности соединения(добавления) указанных цепей, см. последний пример.Все функции переданные в метод .end
после начала выполнения цепи будут ждать окончания выполнения цепи, т. е. цепи не будут запущены дважды. Вставьте console.log
в каждую функцию в последнем примере, станет понятней.
Результат выполнения цепи сохраняется и будет возвращаться при каждом вызове метода .end
, цепь запущена не будет. На самом деле, метод .end
может принимать второй аргумент, заставляющий запустить цепь еще раз, но это поведение не доведено до ума. Если Chain.js придется вам по душе, то беру на себя обязательство с этим поведением разобраться.
Также, не реализовано прерывание выполнения цепи, хотя это возможно и легко осуществимо.
Конец
А конец ли? Приветствую ваши комментарии, предложения, пожелания. Спасибо за внимание.
This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:
- Massacres That Matter - Part 1 - 'Responsibility To Protect' In Egypt, Libya And Syria
- Massacres That Matter - Part 2 - The Media Response On Egypt, Libya And Syria
- National demonstration: No attack on Syria - Saturday 31 August, 12 noon, Temple Place, London, UK
Комментариев нет:
Отправить комментарий