Skip to content

Commit d634bcf

Browse files
committed
Use dynamic import for default worker
1 parent cf20236 commit d634bcf

File tree

7 files changed

+54
-42
lines changed

7 files changed

+54
-42
lines changed

README.md

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -296,28 +296,6 @@ const data = await image.readRasters({ pool });
296296
It is possible to provide a pool size (i.e: number of workers), by default the number
297297
of available processors is used.
298298

299-
Because of the way WebWorker work (pun intended), there is a considerable overhead
300-
involved when using the `Pool`, as all the data must be copied and cannot be simply be
301-
shared. But the benefits are two-fold. First: for larger image reads the overall time
302-
is still likely to be reduced and second: the main thread is relieved which helps to
303-
uphold responsiveness.
304-
305-
If you want to use the Worker Pool in a project built with webpack (ex: VueJS or React) you have to install `threads-plugin` and add the plugin to your `webpack.config.js`:
306-
```
307-
npm install -D threads-plugin
308-
```
309-
310-
```javascript
311-
const ThreadsPlugin = require('threads-plugin')
312-
313-
module.exports = {
314-
// ...
315-
plugins: [
316-
new ThreadsPlugin()
317-
]
318-
}
319-
````
320-
321299
### Dealing with visual data
322300

323301
The TIFF specification provides various ways to encode visual data. In the

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
"build:clean": "rimraf dist-node/ dist-browser/ dist-module/",
7777
"build:node": "parcel build dist-module/geotiff.js --target node --out-dir dist-node/",
7878
"build:browser": "parcel build dist-module/geotiff.js --target browser --out-dir dist-browser/ --global GeoTIFF --public-url .",
79-
"build:module": "shx mkdir -p dist-module && shx cp -rf src/* dist-module/ && node scripts/serialize-workers.js",
79+
"build:module": "shx mkdir -p dist-module && shx cp -rf src/* dist-module/ && node scripts/serialize-workers.cjs",
8080
"watch:browser": "run-p watch:module watch:browser:parcel",
8181
"watch:browser:parcel": "parcel watch dist-module/geotiff.js --target browser --out-dir dist-browser/ --global GeoTIFF --public-url .",
8282
"watch:module": "chokidar \"src/*.js\" -c \"npm run build:module\"",
@@ -86,7 +86,7 @@
8686
"dev:clean": "rm -rf dist/ .cache/",
8787
"docs": "rm -rf docs/; jsdoc -c .jsdoc.json -r src README.md -d docs",
8888
"prelint": "npm run build:module",
89-
"lint": "eslint src test scripts .eslintrc.cjs",
89+
"lint": "eslint src test scripts/*.cjs .eslintrc.cjs",
9090
"lint:fix": "npm run lint -- --fix",
9191
"prepare": "npm run build",
9292
"pretest": "npm run lint",
File renamed without changes.

src/pool.js

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { getDecoder } from './compression';
2-
import { create as createWorker } from './worker/decoder';
1+
import { getDecoder } from './compression/index.js';
32

43
const defaultPoolSize = typeof navigator !== 'undefined' ? (navigator.hardwareConcurrency || 2) : 2;
54

@@ -13,19 +12,51 @@ const defaultPoolSize = typeof navigator !== 'undefined' ? (navigator.hardwareCo
1312
class Pool {
1413
/**
1514
* @constructor
16-
* @param {Number} size The size of the pool. Defaults to the number of CPUs
15+
* @param {Number} [size] The size of the pool. Defaults to the number of CPUs
1716
* available. When this parameter is `null` or 0, then the
1817
* decoding will be done in the main thread.
18+
* @param {function(): Worker} [createWorker] A function that creates the decoder worker.
19+
* Defaults to a worker with all decoders that ship with geotiff.js. The `createWorker()`
20+
* function is expected to return a `Worker` compatible with Web Workers. For code that
21+
* runs in Node, [web-worker](https://www.npmjs.com/package/web-worker) is a good choice.
22+
*
23+
* A worker that uses a custom lzw decoder would look like this `my-custom-worker.js` file:
24+
* ```js
25+
* import { addDecoder, getDecoder } from 'geotiff';
26+
* addDecoder(5, () => import('./my-custom-lzw').then(m => m.default));
27+
* self.addEventListener('message', async (e) => {
28+
* const { id, fileDirectory, buffer } = e.data;
29+
* const decoder = await getDecoder(fileDirectory);
30+
* const decoded = await decoder.decode(fileDirectory, buffer);
31+
* self.postMessage({ decoded, id }, [decoded]);
32+
* });
33+
* ```
34+
* The way the above code is built into a worker by the `createWorker()` function
35+
* depends on the used bundler. For most bundlers, something like this will work:
36+
* ```js
37+
* function createWorker() {
38+
* return new Worker(new URL('./my-custom-worker.js', import.meta.url));
39+
* }
40+
* ```
1941
*/
20-
constructor(size = defaultPoolSize) {
42+
constructor(size = defaultPoolSize, createWorker) {
2143
this.workers = null;
44+
this._awaitingDecoder = null;
2245
this.size = size;
2346
this.messageId = 0;
2447
if (size) {
25-
this.workers = [];
26-
for (let i = 0; i < size; i++) {
27-
this.workers.push({ worker: createWorker(), idle: true });
28-
}
48+
this._awaitingDecoder = createWorker ? Promise.resolve(createWorker) : new Promise((resolve) => {
49+
import('./worker/decoder.js').then((module) => {
50+
resolve(module.create);
51+
});
52+
});
53+
this._awaitingDecoder.then((create) => {
54+
this._awaitingDecoder = null;
55+
this.workers = [];
56+
for (let i = 0; i < size; i++) {
57+
this.workers.push({ worker: create(), idle: true });
58+
}
59+
});
2960
}
3061
}
3162

@@ -34,7 +65,10 @@ class Pool {
3465
* @param {ArrayBuffer} buffer the array buffer of bytes to decode.
3566
* @returns {Promise.<ArrayBuffer>} the decoded result as a `Promise`
3667
*/
37-
decode(fileDirectory, buffer) {
68+
async decode(fileDirectory, buffer) {
69+
if (this._awaitingDecoder) {
70+
await this._awaitingDecoder;
71+
}
3872
return this.size === 0
3973
? getDecoder(fileDirectory).then((decoder) => decoder.decode(fileDirectory, buffer))
4074
: new Promise((resolve) => {

src/worker/decoder.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* global globalThis */
22
/* eslint-disable import/no-mutable-exports */
3-
import { getDecoder } from '../compression';
3+
import { getDecoder } from '../compression/index.js';
44

55
const worker = globalThis;
66

test/dev.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* global plotty:false */
2-
import { Pool, fromUrl } from '../dist-module/geotiff';
2+
import { Pool, fromUrl } from '../dist-module/geotiff.js';
33

44
const imageWindow = [0, 0, 500, 500];
55
const tiffs = [

test/geotiff.spec.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ import 'isomorphic-fetch';
88
import AbortController from 'node-abort-controller';
99
import { dirname } from 'path';
1010

11-
import { GeoTIFF, fromArrayBuffer, writeArrayBuffer, fromUrls, Pool } from '../dist-module/geotiff';
12-
import { makeFetchSource } from '../dist-module/source/remote';
13-
import { makeFileSource } from '../dist-module/source/file';
14-
import { BlockedSource } from '../dist-module/source/blockedsource';
15-
import { chunk, toArray, toArrayRecursively, range } from '../dist-module/utils';
16-
import DataSlice from '../dist-module/dataslice';
17-
import DataView64 from '../dist-module/dataview64';
11+
import { GeoTIFF, fromArrayBuffer, writeArrayBuffer, fromUrls, Pool } from '../dist-module/geotiff.js';
12+
import { makeFetchSource } from '../dist-module/source/remote.js';
13+
import { makeFileSource } from '../dist-module/source/file.js';
14+
import { BlockedSource } from '../dist-module/source/blockedsource.js';
15+
import { chunk, toArray, toArrayRecursively, range } from '../dist-module/utils.js';
16+
import DataSlice from '../dist-module/dataslice.js';
17+
import DataView64 from '../dist-module/dataview64.js';
1818

1919
const __dirname = dirname(new URL(import.meta.url).pathname);
2020

0 commit comments

Comments
 (0)