# Multi Web Worker Example

## Introduction

This example is **not** intended for beginners. I will assume that you have understood the [Single Web Worker Example](/ifc-js/web-worker-example/single-web-worker-example.md). If you are unsure how IFC works, then check out: [What is IFC?](https://bimwhale.gitbook.io/bim-whale/ifc/what-is-ifc)

## Background

A `single Web Worker` will not be enough for a large file, say > 20MB.\
Yes, the `Web Worker` runs in the background but its synchronous code.

We can use `multiple` *Web Workers* build asynchronous code.

Check out: [Asynchronous Vs Synchronous Programming](https://www.youtube.com/watch?v=Kpn2ajSa92c)

One might call this approach `multithreading` or `parallelizing`.\
I really don't want to go into technicalities right now\... but for the sake of simplicity.

Let's call this approach:

{% hint style="warning" %}
**Multithreading**
{% endhint %}

This might be a new concept if you only worked with web development.\
If you have a background with C, Java, Python, etc. than this will be easier to understand.

Anyways, let's continue!

## Prerequisites

* A modern Web Browser
* An understanding what multithreading is
* *Patience you must have, my young Padawan*

### Work with modern browsers

In order to do `multithreading` we need to do one thing:

{% hint style="warning" %}
We need to spawn additional, descendant dedicated Web Workers
{% endhint %}

Most modern browser should be able to do this... but not [Safari](https://www.chromestatus.com/feature/6080438103703552).

### Babel

Let's recall that we use [Babel](https://babeljs.io/docs/en/) to build our bundles.\
In more detail, we use the [preset-env](https://babeljs.io/docs/en/babel-preset-env).

**This is where the fun begins:**\
We can use the [Browserslist](https://github.com/browserslist/browserslist) integration. Simply look at the `package.json` file.

```javascript
{
    ...
    "browserslist":"last 2 Chrome versions"
    ...
}
```

## **What and How?**

### What SHOULD we multithread?

First, we need to identify which parts are blocking our code. The original code has three major parts:

1. `loadIfcFileItems`
2. `constructProject`
3. `buildGeometry`

{% code title="src/IFC.js" %}

```javascript
function loadIfc(ifcData) {
    const loaded = loadIfcFileItems(ifcData);
    const structured = constructProject(loaded);
    return buildGeometry(structured);
}
```

{% endcode %}

As we discussed earlier, we cannot build the geometry inside a web worker. That leaves `loadIfcFileItems` and `constructProject`

Let's take a look at this picture:

![](/files/-MSCHUoFQUutoVmpqytR)

Your eyes can deceive you, don't trust them. Instead, trust the [Chrome DevTools Performance panel](https://developers.google.com/web/tools/chrome-devtools/evaluate-performance).

We can see that `loadIfcFileItems` and `constructProject` takes roughly the same amount of time to compute.

### What CAN we multithread?

We must consider one thing.

> What can we parse independently of other IFC entities?

If you know your `A, B, and (IF)C`, then you realize that we cannot do that much. The IFC schema realizes heavily on references to other entities.

Therefore, the only thing we can do is `loadIfcFileItems` independently.

## Using multiple Web Workers

### How do we load IFC file items independently?

The first thing we need to do is to split up the IFC into different parts. One approach is to split the file itself into several parts. My approach is to split each `IfcType` into groups.

In layman's terms:

* Let's load all `properties` using one Web Worker
* Let's load all `materials` using one Web Worker
* Let's load all `building elements` using one Web Worker
* Let's load all `relationships` using one Web Worker
* etc. etc.

See `examples/web-worker/worker/utils/custom-ifc-types.js` for more info.

### How do we construct multiple Web Workers?

Now that we have figured out how to divide our IFC file, let's look at how we spawn our nested `Web Workers`. Take a look at `multi-worker.js`, on line 32:

{% code title="examples/web-worker/worker/multi-worker.js" %}

```javascript
for (const [ifcTypesGroupName, ifcTypesGroup] of Object.entries(ifcTypesGroups)) {
    constructWebWorker(dataSection, ifcTypesGroupName, ifcTypesGroup);
}
```

{% endcode %}

A simple `for loop` will do the trick. Each `Web Worker` can work on its own. Once its done, it will call the function `workerDone`.

{% code title="examples/web-worker/worker/multi-worker.js" %}

```javascript
function workerDone(e) {
    const _loaded = e.data.loaded;
    Object.assign(loaded, _loaded);
    --running;
    if (running === 0) {
        // DO STUFF WHEN DONE
    }
}
```

{% endcode %}

The global variable `loaded` will store ALL the loaded data. In other words: `loaded` will store the result from each web workers.

Since the Web Works parse different IfcTypes, the result will not conflict.

We can do a dirty and quick check to see if multiple `Web Workers` are running.

### Merging the result

We now have all the loaded data. But, remember that we have used specific `Web Workers` to parse the loaded data.

{% hint style="danger" %}
We are missing the references to other entities!
{% endhint %}

We can simply fix this by running this command **AT THE END** (!).

{% code title="examples/web-worker/worker/multi-worker.js" %}

```javascript
IFCjs.referenceEntities(loaded);
```

{% endcode %}

Then its a matter of constructing the project like before.

{% code title="examples/web-worker/worker/multi-worker.js" %}

```javascript
const structured = IFCjs.constructProject(loaded);
postMessage(structured);
```

{% endcode %}

## Final notes

This is a very dirty and simple approach. Take a look at these commits for a general understanding of what I did.

* [Add Multi Web Worker](https://github.com/andrewisen/IFC.js-web-worker-example/commit/80f6ae3a4edc7b3474f15b2ae0364c1c86f3ca30)
* [Remove support for older browsers](https://github.com/andrewisen/IFC.js-web-worker-example/commit/5a09385f82a85b87ca636b07f5ad06ab31089bb7)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bimwhale.gitbook.io/ifc-js/web-worker-example/multi-web-worker-example.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
