Introduction to Shared Memory in JavaScript

Shared memory is an modernized underline of JavaScript, that threads (concurrently executed tools of a process) can leverage. Sharing a memory means not carrying a difficulty of flitting updated information between threads and all threads can entrance and refurbish a same information in a common memory.

Doesn’t that sound lovely? Well, almost. In this post, we’ll see how to use common memory in JavaScript and how to confirm if this is what we unequivocally wish to do.

Advantages disadvantages of common memory

We use web workers to create threads in JavaScript. The Web Workers API allows us to emanate workman threads that can be used to execute formula in a background so that a categorical thread is giveaway to continue a execution, presumably estimate UI events, ensuring no UI freeze.

Worker threads run parallel with a categorical thread and any other. Such coexisting execution of opposite tools of a charge is time-saving. You finish quicker, though it also has a possess set of problems.

Making certain that any thread gets a required resources and communicates with any other in a timely manner is a charge in itself, where a fumble can outcome in a startling outcome. Or, if one thread is changing information and another one is reading it at a same time, what do we consider a other thread will see? The updated or a aged data?

However, web workers are not so easy to screw up. During their communication around regulating messages, a information they send any other is not strange though a copy, definition they don’t share a same data. They pass copies of information to any other when needed.

But pity is caring, and mixed threads competence also need to demeanour during a same information during a same time and change them. So, banning pity is a large no-no. This is where a SharedArrayBuffer intent comes into a picture. It will let us share binary information between mixed threads.

The SharedArrayBuffer object

Instead of flitting a information copies between threads, we pass copies of a SharedArrayBuffer object. A SharedArrayBuffer intent points to a memory where a information is saved.

So, even when a copies of SharedArrayBuffer are upheld between threads, they all will still indicate to a same memory where a strange information is saved. The threads, thus, can view and refurbish a information in that same memory.

Shared Memory and Web Workers DiagramShared Memory and Web Workers Diagram

Web workers without common memory

To see how a web workman works but regulating common memory, we create a workman thread and pass some information to it.

The index.html record binds a main script inside a script/script tag, as we can see it below:

const w = new Worker('worker.js');
var 	n = 9;
w.postMessage(n);

The worker.js record carries a worker script:

onmessage = (e)={
  console.group('[worker]');
  console.log('Data perceived from categorical thread: %i', e.data);
  console.groupEnd();
}

Using a formula above, we get a following output in a console:

[worker]
Data perceived from categorical thread: 9

You can review my aforementioned post on web workers for a full formula reason of a above snippets.

For now, keep in mind that information is sent behind and onward between threads regulating a postMessage() method. The information is received on a other side by a message eventuality handler, as a value of a event’s data property.

Now, if we change a data will it seem updated during a receiving end? Let’s see:

const w = new Worker('worker.js');
var 	n = 9;
w.postMessage(n);
n = 1;

As expected, the information has not been updated:

[worker]
Data perceived from categorical thread: 9

Why would it be, anyway? It’s just a counterpart sent to a workman from a categorical script.

Web workers with common memory

Now, we will use a SharedArrayBuffer object in a same example. We can emanate a new SharedArrayBuffer instance by using a new keyword. The constructor takes one parameter; a length value in bytes, naming a distance of a buffer.

const w = new Worker('worker.js');
buff = new SharedArrayBuffer(1);
var 	arr = new Int8Array(buff);
/* environment information */
arr[0] = 9;
/* promulgation a aegis (copy) to workman */
w.postMessage(buff);

Note that a SharedArrayBuffer intent represents usually a common memory area. To see and change a binary data, we need to use an suitable information structure (a TypedArray or a DataView object).

In a index.html record above, a new SharedArrayBuffer is created, with usually one-byte length. Then, a new Int8Array, that is one form of TypedArray objects, is used to set a information to “9” in a supposing byte space.

onmessage = (e)={
  var arr = new Int8Array(e.data);
  console.group('[worker]');
  console.log('Data perceived from categorical thread: %i', arr[0]);
  console.groupEnd();
}

Int8Array is also used in a worker, to view a information in a buffer.

The expected value appears in a console from a workman thread, that is accurately what we wanted:

[worker]
Data perceived from categorical thread: 9

Now, let’s update a information in a categorical thread to see if a change is reflected in a worker.

const w = new Worker('worker.js'),
buff = new SharedArrayBuffer(1);
var 	arr = new Int8Array(buff);
/* environment information */
arr[0] = 9;
/* promulgation a aegis (copy) to workman */
w.postMessage(buff);
/* changing a information */
arr[0] = 1;

And, as we can see below, a refurbish does simulate inside a worker!

[worker]
Data perceived from categorical thread: 1

But, a formula also needs to work a other approach around: when a value in a workman changes during first, it also needs to be updated when it’s printed from a categorical thread.

In this case, a formula looks like this:

onmessage = (e)={
  var arr = new Int8Array(e.data);
  console.group('[worker]');
  console.log('Data perceived from categorical thread: %i', arr[0]);
  console.groupEnd();
  /* changing a information */
  arr[0] = 7;
  /* posting to a categorical thread */
  postMessage('');
}

The data is altered in a worker and an empty summary is posted to a categorical thread signalling that a information in a aegis has been altered and is prepared for a categorical thread to be outputted.

const w = new Worker('worker.js'),
buff = new SharedArrayBuffer(1);
var 	arr = new Int8Array(buff);
/* environment information */
arr[0] = 9;
/* promulgation a aegis (copy) to workman */
w.postMessage(buff);
/* changing a information */
arr[0] = 1;
/* copy a information after a workman has altered it */
w.onmessage = (e)={
  console.group('[main]');
  console.log('Updated information perceived from workman thread: %i', arr[0]);
  console.groupEnd();
}

And, this works, too! The information in a aegis is same as a information inside a worker.

[worker]
Data perceived from categorical thread: 1
[main]
Updated information perceived from workman thread: 7

The value appears updated in both a cases; both a categorical and workman threads are observation and changing a same data.

Final words

As I’ve mentioned earlier, regulating common memory in JavaScript is not but downsides. It’s adult to developers to safeguard that a sequence of execution happens as predicted and no dual threads are racing to get a same information since no one knows who will take a trophy.

If we are meddlesome in common memory more, have a demeanour during a support of a Atomics object. The Atomics intent can assistance we with some of a hardships, by shortening a indeterminate inlet of reading/writing from a common memory.

Add Comment