Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: Why does penpal use Window#postMessage instead of MessageChannel? #87

Open
zetlen opened this issue Mar 16, 2022 · 2 comments

Comments

@zetlen
Copy link

zetlen commented Mar 16, 2022

MessageChannel has the same features and support matrix as postMessage, but it has a couple of nice extra things. You may have already considered MessageChannel and opted against it; if so, I'd be curious to know why. You might have a good reason that I should avoid them too.

The difference is that a MessageChannel is an independent object that two realms can use instead of sharing the window's global message event stream.

The nice things:

  • Instead of having to check origins on every message event, you only have to check origins once, when using window.postMessage to send the MessageChannel's port to the worker or frame. Once the MessageChannel is handed off, no other origins have a reference to it, so the security model is a little easier to think about.
  • MessageChannels are independent event streams, so you don't need to continuously filter out extraneous messages from other libraries.
  • Potentially a lot less bookkeeping when handling multiple instances.

The change would be an additional step in establishing the link, something like:

(simplified, with fake internal functions)

function connectToChild(child) {
  return new Promise((resolve, reject) => {
    const channel = new MessageChannel();
    channel.port1.addEventListener(function finishSetup(event) {
      try {
        validateOrigin(event.origin, child);
        validateAck(event.data);
        channel.port1.removeEventListener(finishSetup);
        resolve(channel.port1);
      } catch(e) {
        reject(e);
      }
    });
    child.postMessage(somePenpalNonce, [channel.port2);
  });
}
function connectToParent() {
  return new Promise((resolve, reject) => {
    window.addEventListener('message', function receivePort(event) {
      try {
        validateOrigin(event.origin);
        validateSyn(event.data);
        window.removeEventListener(receivePort);
        resolve(event.ports[0]);
      } catch(e) {
        reject(e);
      }
    }
  });
}
@Aaronius
Copy link
Owner

Hey, thanks for asking the question. I wasn't aware of MessageChannel when I was building Penpal. I learned about it in the meantime but just haven't taken the time to explore switching from postMessage. If you'd like to make a pull request, I'd be interested. Otherwise, I'll dig into it when I get the opportunity. Thanks!

@tequilaNiu
Copy link

tequilaNiu commented Aug 22, 2022

I think MessageChannel is better than window.postMessage.Because it's safer and has two-way communication. But, cannot call function like (parent|child).[declare by your self function], only in the following ways: port2.postMessage({ method: yourFunction, params: { ... } }).I don't know if my understanding is wrong or not. Thanks~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants