Giter Club home page Giter Club logo

Comments (12)

Aaronius avatar Aaronius commented on June 18, 2024 2

You have to go through methods like you're talking about. So in your child iframe you might have something like this:

const childModel = {
  max: 5000
};

const connection = Penpal.connectToParent({
  methods: {
    get(name) {
      return childModel[name];
    }
});

And then from the parent:

connection.promise.then(child => child.get('max').then(max => console.log(max)));

from penpal.

loganvolkers avatar loganvolkers commented on June 18, 2024 1

I like the configuration use case, such as using debug to tell a child to operate in debug mode.

IMHO the most common mistake with @gajewsk2's proposal would be someone expects Penpal to create a proxy object instead of freezing the property.

var object = {};
object.debug: true;
object.getDebug: function(){ return object.debug; };

Penpal.connectToParent(object);

object.debug = false;

// Later
child.getDebug().then(debug => debug === child.debug) // Why aren't they equal?

child.debug.get().then(...) // OR! should we provide async getters for props so that mutations can go through

A couple suggestions here:

  • Separate methods from metadata e.g Penpal.connectToParent(methods,metadata). Would help clarify the difference between the static frozen properties and the dynamic methods. Access via parent._metadata.debug.
  • Use Object.freeze to freeze the properties.

** Aside **

For Parent->Child communication the fastest approach wouldn't used PostMessage at all, it would use query params or hash params. That way if you were trying to get the Client to debug, it would happen immediately instead of only after the handshake is complete. I'm not suggesting we do this, just reminding about speediness of passing configuration details.

from penpal.

gajewsk2 avatar gajewsk2 commented on June 18, 2024

Cool, gets the job done. Would it be possible to expose properties as well in a future update? Or does that go against Penpal's design somehow?

from penpal.

Aaronius avatar Aaronius commented on June 18, 2024

It kind of goes against the design. Penpal's primary goal is communication (for which methods are used). Whether you have data models or how you might structure them is outside of its scope.

Something that might be helpful to understand (if you don't already) is that the child object that you get here:

connection.promise.then(child => child.get('max').then(max => console.log(max)));

isn't any actual object that resides inside your iframe. Basically, when the iframe connects to the parent window, it collects any keys that are on the methods object and passes them to the parent window. The parent window then reconstructs an object with the same keys and makes some proxy methods for their values. This object serves as a proxy and becomes your child object in the snippet above. As such, child isn't a "live" object. For example, if you add or remove properties (or changed their values) on the methods object here:

const connection = Penpal.connectToParent({
  methods: {
    get(name) {
      return childModel[name];
    }
});

after connectToParent has been called, the child object that's in the parent wouldn't be updated.

Even though the concept of exposing properties is against the design, I'd still like to know more about how you're thinking such a mechanism would work. If you changed max from the iframe, would you expect the new value to be sent to the parent window to update child.max? If so, you may run into a race condition because iframe communication is asynchronous. In other words, if you tried to access child.max from the parent window at about the same time max is updated from within the iframe, you may not be getting the actual, current value that's been set from within the iframe.

from penpal.

gajewsk2 avatar gajewsk2 commented on June 18, 2024

My view of Penpal was as a more robust postmessage. I use postmessage to pass primitive or static configuration objects one way typically. I wouldn't expect the two way binding to persist for initial connection properties.

EDIT:
The interaction i'm talking about it only for properties from initial connections. I could use PostMate for something like that or just the builtin postmessage, just hoping for something more elegant.

from penpal.

Aaronius avatar Aaronius commented on June 18, 2024

You can pass primitive or static configuration objects back and forth. What I've shown in my original response is a pull methodology. If you want a push methodology (more like postMessage) rather than a pull, you can do so:

From the child:

connection.promise.then(parent => {
  parent.onChildData(childData);
});

From the parent:

const connection = Penpal.connectToChild({
  ...
  methods: {
    onChildData(data) {
      console.log('child data', data);
    }
  }
});

from penpal.

Aaronius avatar Aaronius commented on June 18, 2024

@gajewsk2 Do you have a proposal for what the API would look like in Penpal that would satisfy what you're looking for?

from penpal.

gajewsk2 avatar gajewsk2 commented on June 18, 2024

I'm thinking my ideal api would allow any property type and not have a methods property by default:
From Child

const connection = Penpal.connectToParent({
    get: function(name) {
      return childModel[name];
    },
    someMethod: function(blah){return foo;},
    config:{
      parentOrigin: '*',
      debug: false,
      promise: Promise
    },
    someObj: { 
      oneAndDone: 123, 
      iWontUpdateWithoutAnotherConnnection: 'default'
    }
});

From Parent:

connection.promise.then(parent => {
  // I've already gotten an initial response, 
  //according to the childs signature I can now access someObj syncronously
  console.log(parent.someObj.oneAndDone);
  // methods will continue with usual Penpal async style
  parent.someMethod(parent.someObj).then((foo)=>console.log(foo));
});

I realize users could put methods inside of objects so to support them you would have to go through the nested objects and detect if their type is a function and then Penpal-ify it, but I think this sort of structure makes it feel like you are using objects in a very natural JS way.

from penpal.

gajewsk2 avatar gajewsk2 commented on June 18, 2024

Thoughts on this?

from penpal.

gajewsk2 avatar gajewsk2 commented on June 18, 2024

I'm interested in separating methods and metadata - I think it's a valid concern and thought. And I've personally never seen a valid justification of the speed impact for Object.freeze, but that aside, it certainly would make it clear to the user.

To your side comment, I'm quite familiar with using query params on iframes for these sorts of things, but what do you mean by hash params in this context?

from penpal.

Aaronius avatar Aaronius commented on June 18, 2024

I have the same concerns that @loganvolkers expressed. I'm open to considering an extra metadata param (or something similar) so that it's more clear that the object is not going to be kept up to date after it's sent to other window. Using parent._metadata to access it feels quirky. I don't really like any of the alternatives I can think of either though.

I'd be curious to hear about use cases (other than debug) that this metadata would be useful for where the current design doesn't work well. In my usage, I've just sent initial metadata in a call right after the connection is established. Something like:

connection.promise.then(child => {
  child.setMetadata(someMetadata);
});

from penpal.

Aaronius avatar Aaronius commented on June 18, 2024

At the moment, I'm not convinced that the value this would bring to the library would outweigh the cost of a more complex API. Closing.

from penpal.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.