| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  | --- | 
					
						
							|  |  |  | title: Web Workers | 
					
						
							|  |  |  | --- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Parsing and writing large spreadsheets takes time. During the process, if the | 
					
						
							|  |  |  | SheetJS library is running in the web browser, the website may freeze. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Workers provide a way to off-load the hard work so that the website does not | 
					
						
							|  |  |  | freeze during processing. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note Browser Compatibility | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | IE10+ and modern browsers support basic Web Workers. Some APIs like `fetch` were | 
					
						
							|  |  |  | added later.  Feature testing is highly recommended. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Installation
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In all cases, `importScripts` can load the [Standalone scripts](../getting-started/installation/standalone) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | importScripts("https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For production use, it is highly encouraged to download and host the script. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  | <details><summary><b>ECMAScript Module Support</b> (click to show)</summary> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note Browser Compatibility | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ESM is supported in Web Workers in the Chromium family of browsers (including | 
					
						
							|  |  |  | Chrome and Edge) as well as in Webkit-based browsers (including Safari). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For support in legacy browsers like Firefox, `importScripts` should be used. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | import * as XLSX from "https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs"; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When using modules, the script must be served with the correct MIME type and the | 
					
						
							|  |  |  | Worker constructor must set the `type` option: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const worker_code = `\ | 
					
						
							|  |  |  | /* load standalone script from CDN */ | 
					
						
							|  |  |  | import * as XLSX from "https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs"; | 
					
						
							|  |  |  | // ... do something with XLSX here ... | 
					
						
							|  |  |  | `; | 
					
						
							|  |  |  | const worker = new Worker( | 
					
						
							|  |  |  |   URL.createObjectURL( | 
					
						
							|  |  |  |     new Blob( | 
					
						
							|  |  |  |       [ worker_code ], | 
					
						
							|  |  |  |       // highlight-next-line | 
					
						
							|  |  |  |       { type: "text/javascript" } // second argument to the Blob constructor | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |   ), | 
					
						
							|  |  |  |   // highlight-next-line | 
					
						
							|  |  |  |   {type: "module"} // second argument to Worker constructor | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  | ## Downloading a Remote File
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  | :::note fetch in Web Workers | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | `fetch` was enabled in Web Workers in Chrome 42 and Safari 10.3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Typically the Web Worker performs the `fetch` operation, processes the workbook, | 
					
						
							|  |  |  | and sends a final result to the main browser context for processing. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In the following example, the script: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - downloads <https://sheetjs.com/pres.numbers> in a Web Worker | 
					
						
							|  |  |  | - loads the SheetJS library and parses the file in the Worker | 
					
						
							|  |  |  | - generates an HTML string of the first table in the Worker | 
					
						
							|  |  |  | - sends the string to the main browser context | 
					
						
							|  |  |  | - adds the HTML to the page in the main browser context | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```jsx live | 
					
						
							|  |  |  | function SheetJSFetchDLWorker() { | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  |   const [__html, setHTML] = React.useState(""); | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return ( <> | 
					
						
							|  |  |  |     <button onClick={() => { | 
					
						
							|  |  |  |       /* this mantra embeds the worker source in the function */ | 
					
						
							|  |  |  |       const worker = new Worker(URL.createObjectURL(new Blob([`\ | 
					
						
							|  |  |  | /* load standalone script from CDN */ | 
					
						
							|  |  |  | importScripts("https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* this callback will run once the main context sends a message */ | 
					
						
							|  |  |  | self.addEventListener('message', async(e) => { | 
					
						
							|  |  |  |   try { | 
					
						
							|  |  |  |     /* Fetch file */ | 
					
						
							|  |  |  |     const res = await fetch("https://sheetjs.com/pres.numbers"); | 
					
						
							|  |  |  |     const ab = await res.arrayBuffer(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Parse file */ | 
					
						
							|  |  |  |     const wb = XLSX.read(ab); | 
					
						
							|  |  |  |     const ws = wb.Sheets[wb.SheetNames[0]]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Generate HTML */ | 
					
						
							|  |  |  |     const html = XLSX.utils.sheet_to_html(ws); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Reply with result */ | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  |     postMessage({ html }); | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  |   } catch(e) { | 
					
						
							|  |  |  |     /* Pass the error message back */ | 
					
						
							|  |  |  |     postMessage({html: String(e.message || e).bold() }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }, false); | 
					
						
							|  |  |  |       `]))); | 
					
						
							|  |  |  |       /* when the worker sends back the HTML, add it to the DOM */ | 
					
						
							|  |  |  |       worker.onmessage = function(e) { setHTML(e.data.html); }; | 
					
						
							|  |  |  |       /* post a message to the worker */ | 
					
						
							|  |  |  |       worker.postMessage({}); | 
					
						
							|  |  |  |     }}><b>Click to Start</b></button> | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  |     <div dangerouslySetInnerHTML={{ __html }}/> | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  |   </> ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Creating a Local File
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  | :::caution Writing files from Web Workers | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | `XLSX.writeFile` will not work in Web Workers!  Raw file data can be passed from | 
					
						
							|  |  |  | the Web Worker to the main browser context for downloading. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In the following example, the script: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - generates a workbook object in the Web Worker | 
					
						
							|  |  |  | - generates a XLSB file using `XLSX.write` in the Web Worker | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | - generates an object URL in the Web Worker | 
					
						
							|  |  |  | - sends the object URL to the main browser context | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  | - performs a download action in the main browser context | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```jsx live | 
					
						
							|  |  |  | function SheetJSWriteFileWorker() { | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  |   const [__html, setHTML] = React.useState(""); | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return ( <> | 
					
						
							|  |  |  |     <button onClick={() => { setHTML(""); | 
					
						
							|  |  |  |       /* this mantra embeds the worker source in the function */ | 
					
						
							|  |  |  |       const worker = new Worker(URL.createObjectURL(new Blob([`\ | 
					
						
							|  |  |  | /* load standalone script from CDN */ | 
					
						
							|  |  |  | importScripts("https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* this callback will run once the main context sends a message */ | 
					
						
							|  |  |  | self.addEventListener('message', async(e) => { | 
					
						
							|  |  |  |   try { | 
					
						
							|  |  |  |     /* Create a new Workbook (in this case, from a CSV string) */ | 
					
						
							|  |  |  |     const csv = \`\ | 
					
						
							|  |  |  | SheetJS,in,Web,Workers | 
					
						
							|  |  |  | வணக்கம்,สวัสดี,你好,가지마 | 
					
						
							|  |  |  | 1,2,3,4\`; | 
					
						
							|  |  |  |     const wb = XLSX.read(csv, { type: "string" }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  |     /* Write XLSB data (Uint8Array) */ | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  |     const u8 = XLSX.write(wb, { bookType: "xlsb", type: "buffer" }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  |     /* Generate URL */ | 
					
						
							|  |  |  |     const url = URL.createObjectURL(new Blob([u8])); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  |     /* Reply with result */ | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  |     postMessage({ url }); | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  |   } catch(e) { | 
					
						
							|  |  |  |     /* Pass the error message back */ | 
					
						
							|  |  |  |     postMessage({error: String(e.message || e).bold() }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }, false); | 
					
						
							|  |  |  |       `]))); | 
					
						
							|  |  |  |       /* when the worker sends back the data, create a download */ | 
					
						
							|  |  |  |       worker.onmessage = function(e) { | 
					
						
							|  |  |  |         if(e.data.error) return setHTML(e.data.error); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* this mantra is the standard HTML5 download attribute technique */ | 
					
						
							|  |  |  |         const a = document.createElement("a"); | 
					
						
							|  |  |  |         a.download = "SheetJSWriteFileWorker.xlsb"; | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  |         a.href = e.data.url; | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  |         document.body.appendChild(a); | 
					
						
							|  |  |  |         a.click(); | 
					
						
							|  |  |  |         document.body.removeChild(a); | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |       /* post a message to the worker */ | 
					
						
							|  |  |  |       worker.postMessage({}); | 
					
						
							|  |  |  |     }}><b>Click to Start</b></button> | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  |     <div dangerouslySetInnerHTML={{ __html }}/> | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  |   </> ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## User-Submitted File
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  | :::note FileReaderSync | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Typically `FileReader` is used in the main browser context. In Web Workers, the | 
					
						
							|  |  |  | synchronous version `FileReaderSync` is more efficient. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  | In the following example, when a file is dropped over the DIV or when the INPUT | 
					
						
							|  |  |  | element is used to select a file, the script: | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | - sends the `File` object to the Web Worker | 
					
						
							|  |  |  | - loads the SheetJS library and parses the file in the Worker | 
					
						
							|  |  |  | - generates an HTML string of the first table in the Worker | 
					
						
							|  |  |  | - sends the string to the main browser context | 
					
						
							|  |  |  | - adds the HTML to the page in the main browser context | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```jsx live | 
					
						
							|  |  |  | function SheetJSDragDropWorker() { | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  |   const [__html, setHTML] = React.useState(""); | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  |   /* suppress default behavior for drag and drop */ | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  |   function suppress(e) { e.stopPropagation(); e.preventDefault(); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  |   /* this worker is shared between drag-drop and file input element */ | 
					
						
							|  |  |  |   const worker = new Worker(URL.createObjectURL(new Blob([`\ | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  | /* load standalone script from CDN */ | 
					
						
							|  |  |  | importScripts("https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* this callback will run once the main context sends a message */ | 
					
						
							| 
									
										
										
										
											2022-10-19 21:12:12 +00:00
										 |  |  | self.addEventListener('message', (e) => { | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  |   try { | 
					
						
							|  |  |  |     /* Read file data */ | 
					
						
							|  |  |  |     const ab = new FileReaderSync().readAsArrayBuffer(e.data.file); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Parse file */ | 
					
						
							|  |  |  |     const wb = XLSX.read(ab); | 
					
						
							|  |  |  |     const ws = wb.Sheets[wb.SheetNames[0]]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Generate HTML */ | 
					
						
							|  |  |  |     const html = XLSX.utils.sheet_to_html(ws); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Reply with result */ | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  |     postMessage({ html }); | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  |   } catch(e) { | 
					
						
							|  |  |  |     /* Pass the error message back */ | 
					
						
							|  |  |  |     postMessage({html: String(e.message || e).bold() }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }, false); | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  |   `]))); | 
					
						
							|  |  |  |     /* when the worker sends back the HTML, add it to the DOM */ | 
					
						
							|  |  |  |     worker.onmessage = function(e) { setHTML(e.data.html); }; | 
					
						
							|  |  |  |   return ( <> | 
					
						
							|  |  |  |     <div onDragOver={suppress} onDragEnter={suppress} onDrop={(e) => { | 
					
						
							|  |  |  |       suppress(e); | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  |       /* post a message with the first File to the worker */ | 
					
						
							|  |  |  |       worker.postMessage({ file: e.dataTransfer.files[0] }); | 
					
						
							| 
									
										
										
										
											2022-10-21 00:10:10 +00:00
										 |  |  |     }}>Drag a file to this DIV to process! (or use the file input)</div> | 
					
						
							|  |  |  |     <input type="file" onChange={(e) => { | 
					
						
							|  |  |  |       suppress(e); | 
					
						
							|  |  |  |       /* post a message with the first File to the worker */ | 
					
						
							|  |  |  |       worker.postMessage({ file: e.target.files[0] }); | 
					
						
							|  |  |  |     }}/> | 
					
						
							|  |  |  |     <div dangerouslySetInnerHTML={{ __html }}/> | 
					
						
							| 
									
										
										
										
											2022-10-19 10:05:59 +00:00
										 |  |  |   </> ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` |