addEventListener и Promise

251
27 марта 2018, 03:19

Ситуация следующая. Есть какой-то класс A, при создании которого в конструкторе на определенный узел DOM должен быть навешен обработчик. При срабатывании события, зарегистрированного этим обработчиком должно вывестись сообщение и вызваться метод _handleCall().

Я решил попробовать реализовать при помощи Promise'ов:

class A {
    constructor() {
        this._waitForCall().then(_handleCall);
    }
    _waitForCall() {
        return new Promise((resolve, reject) => {
            let handler = (event) => {
                console.log("called.");
                resolve(event);
            };
            this.target.addEventListener("click", handler);
        });
    }
    _handleCall(event) {
        console.log(event);
    }
}

Однако я заметил, что при таком подходе метод _handleCall вызывается только один раз, хотя сообщение "called." из обработчика handler выводится при каждом клике на элементе.

Насколько я понимаю, так происходит потому, что у каждого Promise'а есть некое состояние, которое может измениться только единожды. И после его изменения в "fulfilled" (которое происходит после первого нажатия по элементу), метод then на Promise'е уже больше никогда вызван не будет. И отсюда первый вопрос: правильно ли я это понимаю?

В общем, я решил, что ситуацию можно исправив, добавив в _handleCall повторную регистрацию Promise'а:

_handleCall(event) {
    console.log(event);
    this._waitForCall().then((e) => this._handleCall(e));
}

Однако здесь ситуация тоже неоднозначно. Прежде всего плохо то, что при таком подходе на элементе this.target обработчик один и тот же будет регистрироваться n-ое количество раз, что ни есть хорошо. И, хотя эта проблема довольно легко решается, мне все равно кажется, что такой подход - ужасный костыль. Правильно ли я понимаю (и это второй вопрос), что Promise'ы для того и нужны, чтобы обрабатывать какой-то асинхронный код единожды?

Ну и здесь же возникает третий вопрос: а стоит ли вообще работать с событиями и их обработчиками при помощи Promise'ов? Я изначально решил, что стоит, потому что события, они, вроде как, асинхронные. А сейчас принято с любым асинхронным кодом работать при помощи Promise'ов. Но ведь с другой стороны обработчики навешиваются по той же причине. И я с таким же успехом мог бы реализовать все примерно так:

class A {
    constructor() {
        this._registerCallEventListener(); // просто вызываем метод, навешивающий обработчик
    }
    _registerCallEventListener() {
        let handler = (event) => {
            console.log("called.");
            this._handleCall(event); // вызываем напрямую
        };
        this.target.addEventListener("click", handler);
    }
    _handleCall(event) {
        console.log(event);
    }
}

В общем, как лучше поступить?

READ ALSO
Убрать _id из запроса данных mongoDB

Убрать _id из запроса данных mongoDB

Есть бд в которой находятся 3 значения:

270
Как вызвать функцию объекта, если имя объекта и имя функции хранятся в переменной?

Как вызвать функцию объекта, если имя объекта и имя функции хранятся в переменной?

Как вызвать функцию объекта, если имя объекта и имя функции хранятся в переменной?

209
Как значение функции вернуть в html?

Как значение функции вернуть в html?

Мне нужно задать объекту рандомный цветРандомный цвет делает функция, но вопрос в том, как значение этой функции установить в CSS?

240
Почему не работает валидатор в Angular 5

Почему не работает валидатор в Angular 5

Есть попытка создания собственного валидатора для формы в Angular 5 :

189