代码之家  ›  专栏  ›  技术社区  ›  stevendesu

如何避免JavaScript中的函数循环依赖?

  •  0
  • stevendesu  · 技术社区  · 6 年前

    有一个特别的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 函数,我正在引用 onError 之前 出错 在代码中定义得更低。这其实不是问题,因为 开放式 方法将在之后运行 出错 已经定义好了,但这仍然是不好的做法和绊倒 ESLint's no-use-before-define rule

    在更一般的意义上,这是一个错误,当存在两个函数时,每个函数都需要相互引用:

    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 回复  |  直到 6 年前
        1
  •  1
  •   Alex Yokisama    6 年前

    我不认为这是个真正的问题,因为通常一切都很好。你也担心你提到的事实 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);
    
        2
  •  2
  •   Bergi    6 年前

    这仍然是不好的做法和绊倒 ESLint's no-use-before-define rule

    不,这不是一个坏习惯,这是非常必要的。当您具有循环函数依赖关系时,它是首选模式。相应地配置eslint(使用 { "functions": false } )

    是否有消除这种循环依赖的设计模式?

    不是真的。但是,有几个解决方法,例如使用 var (这足以 make ESLint happy )或者,可以通过参数传递对函数的引用:

    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 Combinator的想法,是可以想象的。不过,这并不适合您的事件侦听器场景。