Как избежать функциональной циклической зависимости в JavaScript? - PullRequest
0 голосов
/ 18 декабря 2018

Существует определенный шаблон JavaScript, который всегда беспокоил меня, и я так и не нашел правильный способ его решения.Вместо этого я обычно просто игнорирую это, потому что 99% интерпретаторов JavaScript поддерживают подъем функций, поэтому ошибок во время выполнения не возникает.

Рассмотрим следующее:

function onOpen()
{
    console.log("Connected!");
    ws.removeEventListener("open", onOpen);
    ws.removeEventListener("error", onError);
}

function onError()
{
    console.log("Failed to connect!");
    ws.removeEventListener("message", onMessage);
    ws.removeEventListener("error", onError);
}

var ws = new WebSocket("...");
ws.addEventListener("open", onOpen);
ws.addEventListener("error", onError);

В этом коде в пределах onOpen function, я ссылаюсь на onError до того, как onError было определено ниже в коде.На самом деле это не проблема, потому что метод onOpen не будет работать до тех пор, пока не будет определено onError, но это все еще плохая практика и приводит к отключению правила ESLint «no-use-before-define»

В более общем смысле это ошибка, которая возникает, когда существуют две функции, каждая из которых должна ссылаться друг на друга:

function a(x) {
    return x === 1 ? b(x) : 2;
}
function b(x) {
    return x === 2 ? a(x) : 1;
}

Существует ли шаблон проектирования для устранения этой циклической зависимости?В моем простом обобщенном примере простое решение: «иметь только одну функцию»:

function a(x) {
    return x === 1 ? 1 : 2;
}

Однако при привязке слушателей событий это не всегда представляется возможным.

Ответы [ 2 ]

0 голосов
/ 18 декабря 2018

Это по-прежнему плохая практика и срабатывает Правило ESLint «не использовать перед определением»

Нет, это не плохая практика, это очень большая необходимость,Это предпочтительный шаблон, когда у вас есть круговая функциональная зависимость.Настройте ESLint соответствующим образом (с помощью { "functions": false }).

Существует ли шаблон проектирования для устранения этой круговой зависимости?

Не совсем.Однако есть несколько обходных путей, например, объявив функцию заранее с var (этого достаточно, чтобы сделал ESLint счастливым ).В качестве альтернативы, вы можете передать ссылку на функцию через параметры:

function _a(x, f) {
    return x === 1 ? f(x) : 2;
}
function b(x) {
    return x === 2 ? _a(x, b) : 1;
}
function a(x) {
    return _a(x, b);
}

Можно представить другие сумасшедшие хаки с замыканиями, следуя идее комбинатора Y.Это не совсем подходит для вашего сценария прослушивания событий.

0 голосов
/ 18 декабря 2018

Я не думаю, что это настоящая проблема, потому что обычно все работает нормально.Также вас беспокоит тот факт, что вы упоминаете onError до того, как он будет объявлен, но вам не нужно упоминать ws.Но если вам все еще нужно решить эту проблему, я надеюсь, что этот подход сработает.

var eventListenerListOnOpen = [];
var eventListListenerOnError = [];
var eventListListenerOnMessage = [];

var ws;

function removeListedEventListeners(object, eventName, eventListenerList) {
  eventListenerList.forEach(function(listener) {
    object.removeEventListener(eventName, listener);
  });
}

function onOpen() {
  removeListedEventListeners(ws, "open", eventListenerListOnOpen);
  removeListedEventListeners(ws, "error", eventListenerListOnError);
}

function onError() {
  removeListedEventListeners(ws, "message", eventListenerListOnMessage);
  removeListedEventListeners(ws, "error", eventListenerListOnError);
}

ws = new WebSocket("...");
ws.addEventListener("open", onOpen);
eventListenerListOnOpen.push(onOpen);
ws.addEventListener("error", onError);
eventListenerListOnError.push(onError);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...