window 消息事件有时触发不止一次

window message Event firing more than one time sometime

我的页面中有一个 IFrame。我正在使用 postmessage 在父页面和子页面的脚本之间建立通信。我还有一个 polar 来反映 Iframe 在所有使用 cookie 的选项卡中最小化和最大化状态。

但问题是我有一个计数器,当我的子页面发送带有特殊对象的消息时,它实际上会增加。但是消息事件在父页面中触发了不止一次。如果它触发不止一次,计数器就会出错。这种情况不会一直发生。有时它工作得很好,有时却不行。跟极地有关系吗?因为当我对此发表评论时,一切正常。

这是听众

function listenIframe() {
    var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
    var eventer = window[eventMethod];       

    var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

    // Listen to message from child IFrame window
    eventer(messageEvent, function (e) {
        if (e.data == xyz) {
            close();
        } else if (e.data == abcd) {
           //increase Count;
        }
    }, false);
}

这是轮询器

function fn(start) {
    var x, y, z;

    if (start) {
        j.k= setTimeout(function stateChangePollar() {
            // show or hide logic here

            setTimeout(stateChangePollar, 1000);
        }, 1000);
    }
    else {
        clearTimeout(j.k);
    }
}

你的 listenIframe 什么时候来电?难道是被调用了多次?最好的方法是确保它只被调用一次,否则一个解决方案是将一些东西存储在外部变量中以检查它,如下所示:

let isListenerAttached = false;

function listenIframe() {
    if (isListenerAttached) return;
    isListenerAttached = true;

    var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
    var eventer = window[eventMethod];       

    var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

    // Listen to message from child IFrame window
    eventer(messageEvent, function (e) {
        if (e.data == xyz) {
            close();
        } else if (e.data == abcd) {
           //increase Count;
        }
    }, false);
}

虽然这不是最佳解决方案,但使用外部变量处理它很容易变得混乱。特别是如果它是一个全局变量。最好的解决方案是确保 listenIframe 只被调用一次。

这可能是因为 addEventListener 调用了不止一次,很可能是在循环中或在不同的文件中。

事实上,每次调用 addEventListener 方法时,都会有一个新的处理函数附加到事件堆栈,并在事件触发时执行。

假设您对 window 对象的 resize 事件感兴趣:

function resizeHandler(e) {
   console.log("Window is resized");
}

window.addEventListener("resize", resizeHandler);
window.addEventListener("resize", resizeHandler);

如果现在调整 window 的大小,您将在控制台中看到:

Window is resized
Window is resized

因此,乍一看似乎事件被调用了多次,而事实是事件只被调用了一次,但多个处理程序正在侦听该事件。

您可以通过确保在您的代码中只有一个 addEventListener 用于该特定事件来解决此问题。