admin管理员组

文章数量:1322013

I'm trying to open a popup window, do some stuff, and send a message back to the opening window so I can do some more stuff with the data it sends.

Essentially, I'm adapting the process outlined here.

This is my code on the "opening window". It runs when a social connect button is clicked. The code opens a popup window and assigns a listener event on the opening window to receive a message from the popup:

//Do the operation
let windowObjectReference = null;
let previousUrl = null;

const openSignInWindow = (url, name) => {

    // remove any existing event listeners
    window.removeEventListener('message', receiveMessage);

    // window features
    const strWindowFeatures =
        'toolbar=no, menubar=no, width=600, height=700, top=100, left=100';

    if (windowObjectReference === null || windowObjectReference.closed) {
        /* if the pointer to the window object in memory does not exist
         or if such pointer exists but the window was closed */
        windowObjectReference = window.open(url, name, strWindowFeatures);
    } else if (previousUrl !== url) {
        /* if the resource to load is different,
         then we load it in the already opened secondary window and then
         we bring such window back on top/in front of its parent window. */
        windowObjectReference = window.open(url, name, strWindowFeatures);
        windowObjectReference.focus();
    } else {
        /* else the window reference must exist and the window
         is not closed; therefore, we can bring it back on top of any other
         window with the focus() method. There would be no need to re-create
         the window or to reload the referenced resource. */
        windowObjectReference.focus();
    }

    // add the listener for receiving a message from the popup
    window.addEventListener('message', event => receiveMessage(event), false);

    // assign the previous URL
    previousUrl = url;

};


const receiveMessage = event => {
    // Do we trust the sender of this message? (might be different from what we originally opened, for example).
    if (event.origin !== websiteHomeUrlNoSlash) {
        return;
    }

    const { data } = event;
    console.log(data); //<--- THIS WHERE I'm SEEING DUPLICATES

};

//Invoke the function
openSignInWindow(url, name);

In the popup users login to their social account and then get redirected to a page on my app where the below code is run. The code posts a message back to the opening window and then closes the popup:

// Get the message data
const messageObj = {
    pluginReason: pluginReasonVar,
    displayName: displayNameVar,
    provider: providerVar,
};

if (window.opener) {
    // send them to the opening window
    window.opener.postMessage(messageObj, websiteHomeUrlNoSlash);
    // close the popup
    if (closePopup) {
        window.close();
    }
}

Everything almost works as expected. Users can login to their social accounts and all the redirections and opening and closing of the popup works fine.

The Problem:

If users go through the Social Connect process multiple times without refreshing the page, then the message data that is printed to the console is duplicated more and more each run.

For example:

  • On the 1st run console.log(data) is printed once. So far this works as expected.
  • On the 2nd run console.log(data) prints twice. It should only be printed once.
  • On the 3rd run console.log(data) prints three times. It should only be printed once.

Each time the Social Connect process is run it should only print once. But somehow it's adding a duplicate copy on each subsequent run.

This duplication keeps growing until the users refreshes the page, which starts the count back at one.

I want to do more data manipulation at the point of the console.log(data) but I can't do that while it's creating duplicates copies on each subsequent run.

How do I stop that from happening?

Maybe it's because the listener event is not detaching? If so, how do I fix that?

I'm trying to open a popup window, do some stuff, and send a message back to the opening window so I can do some more stuff with the data it sends.

Essentially, I'm adapting the process outlined here.

This is my code on the "opening window". It runs when a social connect button is clicked. The code opens a popup window and assigns a listener event on the opening window to receive a message from the popup:

//Do the operation
let windowObjectReference = null;
let previousUrl = null;

const openSignInWindow = (url, name) => {

    // remove any existing event listeners
    window.removeEventListener('message', receiveMessage);

    // window features
    const strWindowFeatures =
        'toolbar=no, menubar=no, width=600, height=700, top=100, left=100';

    if (windowObjectReference === null || windowObjectReference.closed) {
        /* if the pointer to the window object in memory does not exist
         or if such pointer exists but the window was closed */
        windowObjectReference = window.open(url, name, strWindowFeatures);
    } else if (previousUrl !== url) {
        /* if the resource to load is different,
         then we load it in the already opened secondary window and then
         we bring such window back on top/in front of its parent window. */
        windowObjectReference = window.open(url, name, strWindowFeatures);
        windowObjectReference.focus();
    } else {
        /* else the window reference must exist and the window
         is not closed; therefore, we can bring it back on top of any other
         window with the focus() method. There would be no need to re-create
         the window or to reload the referenced resource. */
        windowObjectReference.focus();
    }

    // add the listener for receiving a message from the popup
    window.addEventListener('message', event => receiveMessage(event), false);

    // assign the previous URL
    previousUrl = url;

};


const receiveMessage = event => {
    // Do we trust the sender of this message? (might be different from what we originally opened, for example).
    if (event.origin !== websiteHomeUrlNoSlash) {
        return;
    }

    const { data } = event;
    console.log(data); //<--- THIS WHERE I'm SEEING DUPLICATES

};

//Invoke the function
openSignInWindow(url, name);

In the popup users login to their social account and then get redirected to a page on my app where the below code is run. The code posts a message back to the opening window and then closes the popup:

// Get the message data
const messageObj = {
    pluginReason: pluginReasonVar,
    displayName: displayNameVar,
    provider: providerVar,
};

if (window.opener) {
    // send them to the opening window
    window.opener.postMessage(messageObj, websiteHomeUrlNoSlash);
    // close the popup
    if (closePopup) {
        window.close();
    }
}

Everything almost works as expected. Users can login to their social accounts and all the redirections and opening and closing of the popup works fine.

The Problem:

If users go through the Social Connect process multiple times without refreshing the page, then the message data that is printed to the console is duplicated more and more each run.

For example:

  • On the 1st run console.log(data) is printed once. So far this works as expected.
  • On the 2nd run console.log(data) prints twice. It should only be printed once.
  • On the 3rd run console.log(data) prints three times. It should only be printed once.

Each time the Social Connect process is run it should only print once. But somehow it's adding a duplicate copy on each subsequent run.

This duplication keeps growing until the users refreshes the page, which starts the count back at one.

I want to do more data manipulation at the point of the console.log(data) but I can't do that while it's creating duplicates copies on each subsequent run.

How do I stop that from happening?

Maybe it's because the listener event is not detaching? If so, how do I fix that?

Share Improve this question edited Jan 13, 2021 at 6:31 TinyTiger asked Jan 13, 2021 at 3:14 TinyTigerTinyTiger 2,11112 gold badges65 silver badges131 bronze badges 4
  • 1 I think you just need to {EventTarget}.removeEventListener() after the window close. otherwise you duplicate the listeners – Shir Gans Commented Jan 13, 2021 at 3:28
  • The event listener is on the opening window, not the popup. Trying to remove it from the popup (where window.close(); sits) just throws a ReferenceError because no event listener is defined on that window. Also I've already added a window.removeEventListener('message', receiveMessage); to the opening window. You can find it on the first line inside openSignInWindow. That should remove any existing event listeners on the opening window. Maybe the problem isn't the event listener not detaching but something else? – TinyTiger Commented Jan 13, 2021 at 5:29
  • Consider using developer.mozilla/en-US/docs/Web/API/Broadcast_Channel_API instead of the postMessage api, your problem will then go away by itself. See stackoverflow./a/53876900/2494754 – NVRM Commented Jan 13, 2021 at 5:56
  • Thanks but browser support for Broadcast Channel is 76.26% (caniuse./broadcastchannel) while Post Message is 96.29% (caniuse./mdn-api_window_postmessage). So in this case I need to go with Post Message because it has better support. – TinyTiger Commented Jan 13, 2021 at 6:02
Add a ment  | 

1 Answer 1

Reset to default 8

You have created an anonymous method (event) => { } as a wrapper and attached it to the addEventListener method.

window.addEventListener('message', event => receiveMessage(event), false);

It can't be removed by

window.removeEventListener('message', receiveMessage);

To fix it, make changes like this:

window.addEventListener('message', receiveMessage, false);

Meanwhile, if the method receiveMessage gets lost every time the window has been closed, it's better to move the removeEventListener part inside the receiveMessage.

const receiveMessage = (event)=> {
  window.removeEventListener('message', receiveMessage);
  // do something else
}

本文标签: popupwindowWhy does JavaScript quotwindowpostMessagequot create duplicate messagesStack Overflow