diff --git a/lib/ImageWorker.js b/lib/ImageWorker.js
index 743e1c9..53869de 100644
--- a/lib/ImageWorker.js
+++ b/lib/ImageWorker.js
@@ -3,15 +3,10 @@
import React, { Component } from 'react';
const webWorkerScript = `
+ const handleResponse = response => response.blob();
self.addEventListener('message', event => {
const url = event.data;
- fetch(url, {
- method: 'GET',
- mode: 'no-cors',
- cache: 'default'
- }).then(response => {
- return response.blob();
- }).then(_ => postMessage(url));
+ fetch(url, { mode: 'no-cors' }).then(handleResponse).then(() => postMessage(url));
})
`;
@@ -34,11 +29,44 @@ const wrappedComponent = WrappedComponent => props => {
return ;
};
+/** Have we initiated the worker pool already? */
+let workerPoolCreated = false;
+const workerPool = [];
+
+function createWorkerPool() {
+ const blobURL = URL.createObjectURL(
+ new Blob([webWorkerScript], { type: 'application/javascript' })
+ );
+ for (let i = 0; i < window.navigator.hardwareConcurrency || 4; ++i) {
+ workerPool.push({
+ worker: new Worker(blobURL),
+ inUse: false,
+ i
+ });
+ }
+}
+
+/** Returns the next available worker. */
+function getNextWorker() {
+ for (let i = 0; i < workerPool.length; ++i) {
+ const worker = workerPool[i];
+ if (!worker.inUse) {
+ worker.inUse = true;
+ return worker;
+ }
+ }
+ // no free found, so we just return the first one
+ return workerPool[0];
+}
+
+/** Marks worker `index` as available. */
+function setFree(index: number) {
+ workerPool[index].inUse = false;
+}
+
+
class ImageWorker extends Component {
image: HTMLImageElement;
- worker = new Worker(URL.createObjectURL(
- new Blob([webWorkerScript], { type: 'application/javascript' })
- ))
state = {
isLoading: true,
@@ -46,21 +74,26 @@ class ImageWorker extends Component {
}
constructor(props: ImageWorkerProps) {
super(props);
- this.worker.onmessage = (event: Object) => {
+ this.image = null;
+
+ if (!workerPoolCreated) {
+ workerPoolCreated = true;
+ createWorkerPool();
+ }
+
+ const workerObj = getNextWorker();
+ workerObj.worker.onmessage = (event: Object) => {
this.loadImage(event.data);
+ setFree(workerObj.i);
};
- }
-
- componentDidMount() {
- this.worker.postMessage(this.props.src);
+ workerObj.worker.postMessage(props.src);
}
componentWillUnmount() {
- if (this.image) {
+ if (this.image !== null) {
this.image.onload = null;
this.image.onerror = null;
}
- this.worker.terminate();
}
renderPlaceholder() {
@@ -70,9 +103,8 @@ class ImageWorker extends Component {
return ;
} else if (typeof placeholder === 'string') {
return
;
- } else {
- return null;
}
+ return null;
}
loadImage = (url: string) => {