Preventing nested prototype methods from being transferred between objects in a WebWorker

My challenge is to reserialize an object from a WebWorker while maintaining the same definitions.

However, upon receiving the message, all of the prototype functions are lost.

The current solution I have only works for first level prototype functions, but I need a way to handle nested classes as well (since this object has a complex hierarchy and dependencies).

I'm looking for suggestions on how to achieve that. Any ideas?

This is what the current data model looks like:

https://i.sstatic.net/QrHt0.png

(note the Object prototypes)

By using the flatted library and a custom revive function, I was able to get closer to the desired model. However, some nested references are still not treated as original class objects.

https://i.sstatic.net/SgEKp.png

Here is the code snippet for the flatted revive function:

const model = parse(data, (key, val) => {
  if (val !== null && val.className && val.className in models) {
    if (val.className === "DataProvider") {
       console.log(val)
       return new DataProvider(val.providerData)
    }
    return Object.assign(new (<any>models)[val.className](), val)
   }
   return val;
 })

I am using the flatted library to avoid circular issues with JSON serialization. Here is the link to the library: https://github.com/WebReflection/flatted

For a minimal example of the issue, you can refer to this CodeSandbox demo: https://codesandbox.io/s/zealous-https-n314w?file=/src/index.ts (Object is lost after 2nd level referencing)

Answer β„–1

I must acknowledge the insights shared in this previous answer. However, I respectfully suggest that there may be a more optimal solution to the problem outlined. It's worth noting that I am the creator of the flatted library, which provided assistance and clarification in addressing this specific issue related to the library.

A key aspect missing from the aforementioned answer is the repetitive updating of the same instance during the structure revival process. This can potentially be streamlined by leveraging either a Set or WeakSet to prevent unnecessary repetition of upgrades.

const {setPrototypeOf} = Reflect;
const upgraded = new Set;
const ret = parse(str, (_, v) => {
  if (v && v.className && models[v.className] && !upgraded.has(v)) {
    upgraded.add(v);
    setPrototypeOf(v, models[v.className].prototype);
  }
  return v;
});

This adjustment may not fundamentally alter the functionality, but it aims to enhance performance and reduce redundant updates. By avoiding unnecessary setPrototypeOf calls, the overall efficiency of the process could be improved πŸ˜‰

Answer β„–2

One common issue arises when dealing with circular structures, known as the "tying the knot" problem. During deserialization, the flatted library needs to begin somewhere and pass in the original object that has not yet been revived. While it is possible to use a proxy or objects with getters to parse the involved objects in the correct order on-demand, this approach can lead to a stack overflow if all objects within the circle need to be revived simultaneously. JavaScript lacks lazy evaluation, making it challenging to reference the result of a call before evaluating it.

To address this challenge, a reviver function supporting a lazy approach that delays accessing the passed object until after deserialization is required:

const cache = new WeakMap();
const ret = parse(str, (k, v) => {
  if (cache.has(v)) return cache.get(v);
  if (v && v.className && (<any>models)[v.className]) {
    const instance = new (<any>models)[v.className]();
    cache.set(v, instance);
    for (const p in instance) {
      Object.defineProperty(instance, p, {
        set(x) { v[p] = x; },
        get() { return v[p]; },
        enumerable: true,
      });
    }
    return instance;
  }
  return v;
});

This approach essentially creates a proxy instance over `v`, retrieving its values from there. When flattened ties the knot by assigning revived values to `v` properties, they become available on `instance` as well. Only the `.className` property of `v` is accessed during the reviver call - other properties are deferred until accessed through `ret.something` to contain the revived objects.

A drawback to this method is that all models must declare and initialize their properties upfront. Additionally, model properties are replaced with accessors, potentially conflicting with the internal implementation.

An alternative approach involves forwarding property assignments made by flatted on the original object to the newly created instance post-reviver call:

const cache = new WeakMap();
const ret = parse(str, (k, v) => {
  if (cache.has(v)) return cache.get(v);
  if (v && v.className && (<any>models)[v.className]) {
    const instance = new (<any>models)[v.className]();
    cache.set(v, instance);
    Object.assign(instance, v);
    for (const p in v) {
      Object.defineProperty(v, p, {
        set(x) { instance[p] = x; },
        get() { return instance[p]; },
      });
    }
    return instance;
  }
  return v;
});

This approach mimics how circular references were originally constructed using direct property assignment instead of the model's method. It is essential to document that models must support constructor calls without arguments and direct property assignment to work effectively. If setters are needed, employ accessor properties rather than `set...()` methods.

The simplest and most efficient strategy may involve maintaining the identity of the object returned from the reviver:

const ret = parse(str, (k, v) => {
  if (v && v.className) {
    const model = (<any>models)[v.className];
    if (model && Object.getPrototypeOf(v) != model.prototype) {
      Object.setPrototypeOf(v, model.prototype);
    }
  }
  return v;
});

This solution restores prototype methods by replacing the prototype of the revived object with the expected one. However, models are instantiated without a constructor call, limiting the usage of enumerable getters and private states even if exposed correctly through `.toJSON`.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Advanced Angular2 Services Expansion

I'm looking to enhance an existing angular service (for example, Http). Requirements: The extension of the service should be done through angular's dependency injection It should be possible to extend the service multiple times using a pattern ...

Pass data to PHP using AJAX

Is it possible to pass the variable rowNumber to the PHP file dataSource in this code? function getData(dataSource, divID,rowNumber) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("GET", dataSo ...

How to specify a single kind of JavaScript object using Typescript

Let's say we have an object structured as follows: const obj = [ { createdAt: "2022-10-25T08:06:29.392Z", updatedAt: "2022-10-25T08:06:29.392Z"}, { createdAt: "2022-10-25T08:06:29.392Z", animal: "cat"} ] We ...

Having trouble accessing the height of a div within an Iframe

Here is the issue I am facing: I need my iFrame to adjust its size based on a div within it, but every attempt to retrieve the size of this div results in 0. var childiFrame = document.getElementById("myDiv"); console.log(childiFra ...

Learning the ins and outs of Node.js: Creating a client to connect to a Node.js server and receive broadcast messages

In implementing my nodeJS Server, everything seems to be running smoothly. However, now I am looking to create a client that can receive messages from the server and trigger specific JavaScript functions based on those messages. The process involves: Us ...

What is the best way to arrange an array of objects in JavaScript by numerical order and then alphabetically?

Possible Duplicate: Sorting objects in an array by a field value in JavaScript I'm looking to sort an array of objects both numerically (by id) and alphabetically (by name). However, the current method I'm using is not giving me the desired ...

"Automatically close the fancybox once the form is confirmed in the AJAX success

Having an issue with closing my fancybox after submitting the registration form on my website. I am using the CMS Pro system.... Here is how I display the fancybox with the form: submitHandler: function(form) { var str = $("#subscriber_application"). ...

Tips on creating a keypress function for a div element with the contenteditable attribute

Hey there, I have managed to create a textarea within a div by using -webkit-appearance. However, I am currently struggling to add an event to this div on key press. I have been trying my best to figure it out but seem to be missing something. If you coul ...

The following MongoDB errors unexpectedly popped up: MongoNetworkError: connect ETIMEDOUT and MongoServerSelectionError: connect ETIMEDOUT

I've been working on a React and NextJS App for about a month now, utilizing MongoDB as my database through MongoDB Atlas. I'm currently using the free version of MongoDB Atlas. For the backend, I rely on NextJS's api folder. Everything wa ...

Error message: "The contract is not defined in thirdweb-dev/react

I am currently using thirdweb-dev/react library to interact with a smart contract. However, I am encountering an issue where the contract is showing up as undefined in my code along with the following error message: query.ts:444 Error: Could not ...

Having trouble establishing an HTTPS connection with a Node.js server

After connecting to my server through the console without any errors, I encountered an issue in Chrome where it displayed a message stating This site can’t provide a secure connection local host uses an unsupported protocol. Here is the code snippet: im ...

Unable to showcase information in a jQuery UI popup through AJAX when initially presented

I'm trying to display reviews from my database on a jQuery UI dialog box upon loading, but nothing is showing up. Here are the reviews: {"results":[{"review_text":"good"},{"review_text":"not bad"},{"review_text":"great"}]} Can someone please check m ...

Can the rxjs take operator be utilized to restrict the number of observables yielded by a service?

As someone who is just starting to learn Angular, I am working on a website that needs to display a limited list of 4 cars on the homepage. To achieve this, I have created a service that fetches all the cars from the server. import { Response } from &apos ...

Steps to include a tooltip on a button that triggers a modal

I am currently utilizing Bootstrap and jQuery to enhance the functionality of components in my application. I am specifically looking to incorporate tooltips into certain elements. The tooltips are implemented through jQuery within my index.html page: < ...

Activate Button upon Textbox/Combobox/RadDatePicker Modification through JavaScript

On my ASP.NET form, I have various input elements including textboxes, dropdowns, date pickers, and update buttons. My goal is to enable the update button whenever a user makes a change in any of these fields. To achieve this, I applied a specific CSS cla ...

Handling mouse events with Angular 2 (tracking movement based on current position)

One of the features I want to implement for my user is the ability to move or rotate an object in a canvas using the mouse. The process involves calculating the delta (direction and length) between successive mouse events in order to update the position of ...

React to the Vue: Only activate the event if the key is pressed twice consecutively

In my application, I am creating a unique feature where users can trigger a window to appear by inputting the symbol @ (shift + 50). This will allow them to access predefined variables... <textarea @keyup.shift.50="showWindow"></textarea> My ...

Content within a Row of a Data Table

Hello! I am just starting to learn JavaScript and jQuery. Can you help me with an issue I am experiencing? Basically, I have a table and I need to identify which tr contains a td with the text "Weekly", "Daily", or "Monthly". Once I locate that specific t ...

What is the best way to change an HTML class using PHP?

I'm currently facing a challenge with my "Newsletter Subscription Form". I rely on MailChimp for sending out newsletters and have successfully set up a custom PHP file to redirect visitors after they enter their email. Here's the step-by-step pr ...

Refreshing the Dropdown Menu with Jquery

Looking for a way to create a reusable dropdown menu using css/jquery? Check out this codepen: https://codepen.io/anon/pen/NxXXPg Is there a method to reset the 'active' status when clicking on a blank space or another html element? Here's ...