Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
October 11, 2021 05:26 pm GMT

How Partytown's Sync Communication Works

Recently we announced the alpha version of Partytown, which is a library that helps relocate third-party scripts into a web worker so that the main thread can be dedicated to just running your code. For more information on why a website would benefit from this Id encourage you to also read: Introducing Partytown : Run Third-Party Scripts From a Web Worker. This post is more for the curious and talking through how Partytown works.

Asynchronous postMessage()

Moving long-running and resource intensive tasks into a web worker has been encouraged for many years now. However, the significant constraint is that the communication between the main thread, and web worker, must be asynchronous. Meaning a message sent by one thread does not wait on the other thread to receive it, nor wait on it to return a value.

At the core, postMessage() is basically a fire-and-forget method. This is perfectly fine, and a communication layer can be built around postMessage() so your code can instead use promises, async/await or even callbacks (all of which are asynchronous).

An awesome project that can help you easily use Web Workers is Comlink, which ...removes the mental barrier of thinking about postMessage and hides the fact that you are working with workers. Comlink is great, but at the time of writing this, you still hit the barrier that the calls between the main thread and web worker must be async.

Why Third-Party Scripts Cant Use postMessage()

As I laid out in the first post, in reality you cant just refactor third-party scripts. Theyre hosted from another domain, controlled by another service, and built to handle countless scenarios so they can be executed by billions of different devices worldwide.

However, many scripts like Google Analytics, are just collecting information and posting that data to their servers using navigator.sendBeacon(). This is the best case scenario because Google Analytics is really just a background task. It can happily run on its own schedule and lazily collect and post data in another thread.

The problem, however, is there are still calls to blocking APIs that are not available in the web worker. For example document.title and window.screen.width are commonly used in scripts, but reading that information is blocking. So while Google Analytics itself is a great candidate to run in the background on another thread, it still requires synchronous communication in order to read values from document and window.

Since the third-party scripts must stay as-is, and because web workers must have an asynchronous communication, weve been in this stand-still where the bulk of our performance issues cannot be offloaded into another thread.

With this One Weird Synchronous Trick

This is the fun stuff! Enter the obscure API: Synchronous XMLHttpRequest. In todays web development its a lesser known API for good reason. Basically in the olden days, when we were rocking Adobe Flash, Java applets, and Dreamweavering DHTML, this was pretty common:

var request = new XMLHttpRequest();request.open('GET', '/data.xml', false);  // `false` makes the request synchronousrequest.send(null);

The problem was that in the main thread, this blocking call would lock up the webpage until the response came back. According to MDN:

Synchronous XHR is now in deprecation state. The recommendation is that developers move away from the synchronous API and instead use asynchronous requests.

And in todays web dev landscape, its best to instead use the more modern fetch() API.

However, the web workers ability to execute synchronously is at the core of many tools. Mainly importScripts(), but Synchronous XHR falls in this category too. These synchronous APIs have not been marked as deprecated from within a web worker. A quick Github search for importScripts() shows just how widely used they are. But again, its only available in a web worker!

So, as it turns out...I guess we can make the web worker blocking...

Intercepting Synchronous Requests

When code is executed from within a worker, and only a worker, we can make synchronous HTTP requests, which effectively block the web worker threads execution until the HTTP response comes back. With that power (and with our mad scientist wig on), we have the ability to execute the web worker code as blocking, and then use the HTTP request to asynchronously call postMessage(). Remember, an HTTP request and response is asynchronous. So while the web worker thread may think its sync, we can intercept the actual HTTP request and have an asynchronous response.

This is where the other weird trick comes in. Doctors hate it!

Service workers are able to intercept requests with onfetch. This means that the request the web worker makes can also be intercepted and handled by our own code. The requests are not external and do not hit the actual network, but instead are handled locally within the service worker. From within onfetch, we can then use postMessage() to do the real async communication.

A service worker still doesnt have direct access to the main thread yet. But because were now communicating asynchronously, from within the service worker we can then use its postMessage() to talk to the the main thread, and have the main thread send messages back to the service worker. Then the service worker completes the HTTP response which it already intercepted.

So we still have the same asynchronous constraint, but with the combination of synchronous XHR, and intercepting requests, we can effectively convert an async call into a blocking one. Next, we make it a bit easier to use by wrapping up all the main threads access with Javascript Proxies.

Additionally, Partytown should still work for legacy browsers. Part of its initialization is that if the browser doesnt support service workers, then it basically just runs the third-party scripts the traditional way (what were all doing today).

What About Atomics?

Awesome, glad you asked. Personally, Im hopeful to see Atomics as the solution in the long run. Since the awesome OSS community has stepped up with some great ideas, weve already broken ground on having two builds available: atomics and service workers. When the library runs, itll decide which to use depending on the browsers support.

Currently, the plan is that the service worker trick will ultimately become the fallback, but theres much more Atomics research to do. Good news for the future of Atomics is that Safari Tech Preview just enabled SharedArrayBuffer!

Whats Next

Partytown is still in alpha and undergoing many changes on each commit . But we're already actively running it on a few pages within Builder.io so we can collect more production data.

Additionally, were working with a few ecommerce sites who have significant third-party script usage, and see if we can help improve their performance and usability. Wed love to have you hop in our Discord channel and chat ideas, or even help test and file issues in our Github repo!

So please stay tuned as we continue this experiment. In follow up posts well continue to dig deeper into other parts of the library, and as we gather more data were hoping to present some good hard numbers showing Partytowns benefits.

Party on, Garth!


Original Link: https://dev.to/adamdbradley/how-partytown-s-sync-communication-works-4244

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To