Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Как бы вы переписали этот код (https://javascript.ru/forum/misc/60955-kak-vy-perepisali-ehtot-kod.html)

GayCoder 28.01.2016 19:04

Как бы вы переписали этот код
 
vanished

GayCoder 29.01.2016 06:14

vanished

tsigel 29.01.2016 07:09

В методе emit есть ошибка. Перед тем как пробегать по обработчикам и запускать их события надо сначала сделать копию массива обработчиков, в противном случае, если в одном из обработчиков будут добавляться/удаляться обработчики, то все может сломаться.

tsigel 29.01.2016 07:12

Ну и обычно делаю чтобы метод отписки мог работать и без параметров, в этом случае должны удаляться все обработчики. Очень удобно когда надо грохнуть целую вьюху со всеми обработчиками. Ну и очень круто сделали ребята в бэкбоне. Идея методов listenTo и stopListening - шикарна.

tsigel 29.01.2016 07:17

https://github.com/tsigel/BaseClass/...er/src/Base.ts
Там есть поддержка событий через ":", и тестики.

GayCoder 29.01.2016 08:42

vanished

tsigel 29.01.2016 08:51

GayCoder,
Допустим у меня есть 4 обработчика на 1 событии. Во втором обработчике я вешаю ещё 3 обработчика на это же событие. То есть массив по которому вы бежите изменится в момент выполнения одного из обработчиков. Как раз из-за того что js однопоточен, как вы верно заметили. Но если добавлять - то все хорошо, а если удалять - то всему конец.

Если я в обработчике отпишу следующий обработчик, то индекс собъется и пойдут трудно отлавливаемые баги.

tsigel 29.01.2016 08:54

Цитата:

Сообщение от GayCoder (Сообщение 405407)
> a=[1,2,3,4,5]
[1, 2, 3, 4, 5]
> a.forEach((v, k) => { if (k == 2) a.splice(k, 1); console.log(v); })
1
2
3
5
undefined

Ну как бы даже чисто теоретически никто не может изменить массив пока выполняется цикл. JS то однопоточный.

Что то я не вижу у вас цифру 4 :)

tsigel 29.01.2016 09:02

var EventEmiter = {
    _handlers: [],
    on: function (handler) {
        this._handlers.push(handler);
    },
    off: function (handler) {
        this._handlers.splice(this._handlers.indexOf(handler), 1);
    },
    emit: function () {
        this._handlers.forEach(function (handler) {
            handler();
        });
    }
};

var handler4 = function () {
    console.log(4);
};

EventEmiter.on(function () {
    console.log(1);
});

EventEmiter.on(function () {
    console.log(2);
    EventEmiter.on(function () {
        console.log('Добавил в цикле, не долже проиграться во время текущего события!');
    });
});

EventEmiter.on(function () {
    console.log(3);
    EventEmiter.off(handler4);
});

EventEmiter.on(handler4);

EventEmiter.on(function () {
    console.log(5);
});

EventEmiter.on(function () {
    console.log(6);
});

EventEmiter.emit();


Вот простейшая реализация без копирования массива. Как вы видите обработчик 4 не отработал вовсе, а обработчик который мы навесили во время события добавился, хотя должен был работать только со следующего события.

Обработчики события не должны влиять на работу ТЕКУЩЕГО события, они должны влиять на последующие за событием поведение.

GayCoder 29.01.2016 10:15

vanished

tsigel 29.01.2016 14:04

GayCoder,
Не удобно разделять метод отписки и отписки от всего. Вы теряете гибкость.

куда проще так:
...removeEventListener()//удалили все обработчики
...removeEventListener(someType)//удалили все обработчики конкретного события
...removeEventListener(someType, handler)//удалили конкретный обработчик

GayCoder 29.01.2016 16:42

vanished

tsigel 29.01.2016 18:28

Цитата:

Сообщение от GayCoder
if ({}.hasOwnProperty.call(this._listeners, event)) {

очень странно, а не проще так:
if (this._listeners.hasOwnProperty(event)) {

или
if (event in this._listeners) {

или
if (this._listeners[event]) {

GayCoder 30.01.2016 08:52

vanished

GayCoder 30.01.2016 12:27

vanished

tsigel 30.01.2016 14:54

GayCoder,
Увы, но данная реализация вообще не верна и не имеет права на жизнь. :)
Дело в том что вы в подписке проверяете наличие этой функции в слушателе чего делать категорически нельзя. Допустим у меня есть 2 экземпляра одного класса, и оба подписываются на событие, если метод которым они подписываются лежит в прототипе, то первый подпишется нормально, а второй перетрет его scope (в вашей реализации). Я создал упрощённый макет чтобы продемонстрировать ошибку:

var EventEmiter = {
    _handlers: [],
    on: function (handler, context) {
        if (!this._hasHandler(handler)) {
            this._handlers.push({handler: handler, context: context});
        }
    },
    off: function (handler) {
        this._handlers.splice(this._handlers.indexOf(handler), 1);
    },
    emit: function () {
        this._handlers.slice().forEach(function (handlerData) {
            handlerData.handler.call(handlerData.context);
        });
    },
    _hasHandler: function (handler) {
        return this._handlers.some(function (handlerData) {
            return handlerData.handler === handler;
        });
    }
};

var SomeClass = function (name) {
    this._name = name;
};

SomeClass.prototype.onEvent = function () {
    console.log(this._name);
};

var vasia = new SomeClass('Вася');
var petia = new SomeClass('Петя');

EventEmiter.on(vasia.onEvent, vasia);
EventEmiter.on(petia.onEvent, petia);

EventEmiter.emit();


Как видите отработал только 1 обработчик. В данном случае функция которой они подписываются одна и та же, но она относится к абсолютно разным объектам.

Ну и в методе emit вы почему-то снова не скопировали массив обработчиков перед тем как вызывать события.

GayCoder 30.01.2016 17:50

vanished

GayCoder 30.01.2016 17:58

vanished

GayCoder 30.01.2016 18:38

vanished

tsigel 30.01.2016 21:01

Цитата:

Сообщение от GayCoder
С тем примером правильно работает.

нет, это не правильная работа. В вашем примере в консоли должно быть 13 записей.

Точнее если Вы так и планировали, то может быть оно выполняется как надо, но в общем подходе это работает не так как это реализуют ведущие библиотеки и фреймворки. Это не удобная реализация, на которой не построить сложного приложения

tsigel 30.01.2016 21:02

Посмотрите как реализуют событи Backbone, сравните их поведение с поведением ваших событий.

GayCoder 31.01.2016 03:27

vanished

GayCoder 31.01.2016 10:21

vanished

GayCoder 01.02.2016 08:19

vanished


Часовой пояс GMT +3, время: 19:01.