пятница, 1 апреля 2016 г.

JavaScript Observer, Iterator, Generator, Promise and Observable Patterns

Итератор перебирает подряд набор значений и по очереди выдает элементы iterator.next(), как array.shift()
Генератор по очереди принимает элементы generator.next(1), как array.push(1)
Промис по очереди выполняет цепочку зависимых друг от друга асинхронных событий
Обозреватель добавляет к объекту к объекту функцию события и вызывает её, когда это событие генерируется в коде.
Обозреваемое добавляет к последовательности элементов или асинхронных событий итератор, который по порядку перебирает элементы и обозреватель, который вызывает для перебираемых элементов функции события.
Декоратор обертывает одну функцию в другую функцию decorate(base, wrapper).
Фабрика конструирует объекты по заданным параметрам.
Фасад скрывает сложную функциональность, выдавая вместо неё простую функцию.
Прокси оборачивает функцию в декоратор.

Observer Pattern

// Observer

function Observer () {
    this.events = {};
}

Observer.prototype = {
      addEvent: function (name, func) {if (this.events[name]) {this.events[name].push(func);} else {this.events[name] = [func];}}
    , removeEvent: function (name) {if (this.events[name]) {delete this.events[name];}}
    , dispatchEvent: function (name, args) {if (this.events[name]) {this.events[name].forEach(function (func) {func.apply(null, args);});}}
};

// Observer Test

var observer = new Observer();
observer.addEvent('one', function (a) {console.log('1: ' + a);});
observer.addEvent('one', function (b) {console.log('2: ' + b);});
observer.addEvent('two', function (c) {console.log('3: ' + c);});
observer.dispatchEvent('one', ['one']);
observer.dispatchEvent('two', ['two']);
observer.removeEvent('one');
observer.dispatchEvent('one', ['one']);

Iterator Pattern

// Iterator

function Iterator (items) {
    var i = 0;
    return {
        next: function () {
            var done = (i >= items.length)
                , value = !done ? items[i++] : undefined;
            return {value: value, done: done};
        }
    };
}

// Iterator Test

var iterator = new Iterator([1, 2, 3]);
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {value: 2, done: false}
console.log(iterator.next()); // {value: 3, done: false}
console.log(iterator.next()); // {value: undefined, done: true}

Generator Pattern

// Generator

function Generator (items) {
    var i = 0;
    return {
        next: function (value) {
            items = items.slice();
            var done = (i >= items.length)
            if (!done) {items[i] = value; i++;}
            return {value: items, done: done};
        }
    };
}

// Generator Test

var generator = new Generator(new Array(3));
console.log(generator.next(1)); // {value: [1, undefined, undefined], done: false}
console.log(generator.next(2)); // {value: [1, 2, undefined], done: false}
console.log(generator.next(3)); // {value: [1, 2, 3], done: false}
console.log(generator.next(4)); // {value: [1, 2, 3], done: true}

Promise Pattern

// Promise

function Promise () {
    this.promises = [];
}

Promise.prototype = {
      then: function (success, error) {
        if (Object.prototype.toString.call(success) !== '[object Function]') {success = function () {};}
        if (Object.prototype.toString.call(error) !== '[object Function]') {error = function () {};}
        this.promises.push({success: success, error: error});
        return this;
      }
    , success: function () {
        if (this.promises.length) {
            var args = Array.prototype.slice.call(arguments);
            args.unshift(this);
            this.promises.shift().success.apply(null, args);
        }
      }
    , error: function () {
        if (this.promises.length) {
            this.promises.shift().error.apply(null, arguments);
        }
      }
};

// Promise Test

function timeout1 (seconds, error) {
    var promise = new Promise();
    setTimeout(function () {
        if (seconds > 2) {
            promise.error(seconds);
        } else {
            console.log('Success 1: ' + seconds);
            promise.success(seconds);
        }
    }, seconds * 1000);
    return promise;
}

function timeout2 (promise, seconds) {
    setTimeout(function () {
        if (seconds > 2) {
            promise.error(seconds);
        } else {
            console.log('Success 2: ' + seconds);
            promise.success(seconds);
        }
    }, seconds * 1000);
    return promise;
}

function timeout3 (promise, seconds) {
    setTimeout(function () {
        if (seconds > 1) {
            promise.error(seconds);
        } else {
            console.log('Success 3: ' + seconds);
            promise.success(seconds);
        }
    }, seconds * 1000);
    return promise;
}

function done (promise, seconds) {
    console.log('Done: ' + seconds);
}


function timeout1error (seconds) {console.log('Error 1 seconds: ' + seconds);}
function timeout2error (seconds) {console.log('Error 2 seconds: ' + seconds);}
function timeout3error (seconds) {console.log('Error 3 seconds: ' + seconds);}

timeout1(2).then(timeout2, timeout1error).then(timeout3, timeout2error).then(done, timeout3error);

Observable Pattern = Interator + Promise for async + Observer

Перебираем с помощью итератора все элементы массива или цепочки промисов и для каждого из них тригерим подставленные функции события (успешно, неуспешно, завершено).

// Observable

var Observable = {
    from: function (items) {
        var iterator = new Iterator(items);
        return {subscribe: function (next, error, complete) {
            var item = iterator.next();
            while (!item.done) {
                next(item.value);
                item = iterator.next();
            }
            complete();
        }};
    }
};

// Observable Test

Observable.from(['Adria', 'Jen', 'Sergi']).subscribe(
      function onNext (value) {console.log('Next: ' + value);}
    , function onError (error) {console.log('Error: ' + error);}
    , function onCompleted () {console.log('Completed');}
);

Комментариев нет:

Отправить комментарий