dicom-microscopy-viewer
Version:
Interactive web-based viewer for DICOM Microscopy Images
374 lines (300 loc) • 11.6 kB
HTML
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: webWorker/webWorkerManager.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: webWorker/webWorkerManager.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>// eslint-disable-next-line
import DataLoader from './index.worker.js'
// the taskId to assign to the next task added via addTask()
let nextTaskId = 0
// array of queued tasks sorted with highest priority task first
const tasks = []
// array of web workers to dispatch decode tasks to
const webWorkers = []
const defaultConfig = {
maxWebWorkers: navigator.hardwareConcurrency || 1,
webWorkerTaskPaths: []
}
// limit number of web workers to avoid memory problems in certain browsers
defaultConfig.maxWebWorkers = Math.min(defaultConfig.maxWebWorkers, 7)
let config
const statistics = {
maxWebWorkers: 0,
numWebWorkers: 0,
numTasksQueued: 0,
numTasksExecuting: 0,
numTasksCompleted: 0,
totalTaskTimeInMS: 0,
totalTimeDelayedInMS: 0
}
/**
* Function to start a task on a web worker
*/
function startTaskOnWebWorker () {
// return immediately if no decode tasks to do
if (!tasks.length) {
return
}
// look for a web worker that is ready
for (let i = 0; i < webWorkers.length; i++) {
if (webWorkers[i].status === 'ready') {
// mark it as busy so tasks are not assigned to it
webWorkers[i].status = 'busy'
// get the highest priority task
const task = tasks.shift()
task.start = new Date().getTime()
// update stats with how long this task was delayed (waiting in queue)
const end = new Date().getTime()
statistics.totalTimeDelayedInMS += end - task.added
// assign this task to this web worker and send the web worker
// a message to execute it
webWorkers[i].task = task
webWorkers[i].worker.postMessage(
{
taskType: task.taskType,
workerIndex: i,
data: task.data
},
task.transferList
)
statistics.numTasksExecuting++
return
}
}
// if no available web workers and we haven't started max web workers, start a new one
if (webWorkers.length < config.maxWebWorkers) {
spawnWebWorker()
}
}
/**
* Function to handle a message from a web worker
* @param msg
*/
function handleMessageFromWorker (msg) {
if (msg.data.taskType === 'initialize') {
webWorkers[msg.data.workerIndex].status = 'ready'
startTaskOnWebWorker()
} else {
const start = webWorkers[msg.data.workerIndex].task.start
const action = msg.data.status === 'success' ? 'resolve' : 'reject'
webWorkers[msg.data.workerIndex].task.deferred[action](msg.data.result)
webWorkers[msg.data.workerIndex].task = undefined
statistics.numTasksExecuting--
webWorkers[msg.data.workerIndex].status = 'ready'
statistics.numTasksCompleted++
const end = new Date().getTime()
statistics.totalTaskTimeInMS += end - start
startTaskOnWebWorker()
}
}
/**
* Spawns a new web worker
*/
function spawnWebWorker () {
// prevent exceeding maxWebWorkers
if (webWorkers.length >= config.maxWebWorkers) {
return
}
const worker = new DataLoader()
// spawn the webworker
webWorkers.push({
worker,
status: 'initializing'
})
worker.addEventListener('message', handleMessageFromWorker)
worker.postMessage({
taskType: 'initialize',
workerIndex: webWorkers.length - 1,
config
})
}
/**
* Initialization function for the web worker manager - spawns web workers
* @param configObject
*/
function initialize (configObject) {
configObject = configObject || defaultConfig
// prevent being initialized more than once
if (config) {
return
}
config = configObject
config.maxWebWorkers =
config.maxWebWorkers || navigator.hardwareConcurrency || 1
}
/**
* Terminate all running web workers.
*/
function terminateAllWebWorkers () {
for (let i = 0; i < webWorkers.length; i++) {
webWorkers[i].worker.terminate()
}
webWorkers.length = 0
config = undefined
}
/**
* dynamically loads a web worker task
* @param sourcePath
* @param taskConfig
*/
function loadWebWorkerTask (sourcePath, taskConfig) {
// add it to the list of web worker tasks paths so on demand web workers
// load this properly
config.webWorkerTaskPaths.push(sourcePath)
// if a task specific configuration is provided, merge it into the config
if (taskConfig) {
config.taskConfiguration = Object.assign(
config.taskConfiguration,
taskConfig
)
}
// tell each spawned web worker to load this task
for (let i = 0; i < webWorkers.length; i++) {
webWorkers[i].worker.postMessage({
taskType: 'loadWebWorkerTask',
workerIndex: webWorkers.length - 1,
sourcePath,
config
})
}
}
/**
* Function to add a decode task to be performed
*
* @param taskType - the taskType for this task
* @param data - data specific to the task
* @param priority - optional priority of the task (defaults to 0), > 0 is higher, < 0 is lower
* @param transferList - optional array of data to transfer to web worker
*
* @returns {*}
*/
function addTask (taskType, data, priority = 0, transferList) {
if (!config) {
initialize()
}
let deferred = {}
const promise = new Promise((resolve, reject) => {
deferred = {
resolve,
reject
}
})
// find the right spot to insert this decode task (based on priority)
let i
for (i = 0; i < tasks.length; i++) {
if (tasks[i].priority < priority) {
break
}
}
const taskId = nextTaskId++
// insert the decode task at position i
tasks.splice(i, 0, {
taskId,
taskType,
status: 'ready',
added: new Date().getTime(),
data,
deferred,
priority,
transferList
})
// try to start a task on the web worker since we just added a new task and a web worker may be available
startTaskOnWebWorker()
return {
taskId,
promise
}
}
/**
* Changes the priority of a queued task
* @param taskId - the taskId to change the priority of
* @param priority - priority of the task (defaults to 0), > 0 is higher, < 0 is lower
* @returns boolean - true on success, false if taskId not found
*/
function setTaskPriority (taskId, priority = 0) {
// search for this taskId
for (let i = 0; i < tasks.length; i++) {
if (tasks[i].taskId === taskId) {
// taskId found, remove it
const task = tasks.splice(i, 1)[0]
// set its priority
task.priority = priority
// find the right spot to insert this decode task (based on priority)
for (i = 0; i < tasks.length; i++) {
if (tasks[i].priority < priority) {
break
}
}
// insert the decode task at position i
tasks.splice(i, 0, task)
return true
}
}
return false
}
/**
* Cancels a queued task and rejects
* @param taskId - the taskId to cancel
* @param reason - optional reason the task was rejected
* @returns boolean - true on success, false if taskId not found
*/
function cancelTask (taskId, reason) {
// search for this taskId
for (let i = 0; i < tasks.length; i++) {
if (tasks[i].taskId === taskId) {
// taskId found, remove it
const task = tasks.splice(i, 1)
task.deferred.reject(reason)
return true
}
}
return false
}
/**
* Function to return the statistics on running web workers
* @returns object containing statistics
*/
function getStatistics () {
statistics.maxWebWorkers = config.maxWebWorkers
statistics.numWebWorkers = webWorkers.length
statistics.numTasksQueued = tasks.length
return statistics
}
export default {
initialize,
loadWebWorkerTask,
addTask,
getStatistics,
setTaskPriority,
cancelTask,
webWorkers,
terminateAllWebWorkers
}
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Namespaces</h3><ul><li><a href="annotation.html">annotation</a></li><li><a href="api.html">api</a></li><li><a href="color.html">color</a></li><li><a href="events.html">events</a></li><li><a href="mapping.html">mapping</a></li><li><a href="metadata.html">metadata</a></li><li><a href="opticalPath.html">opticalPath</a></li><li><a href="roi.html">roi</a></li><li><a href="scoord3d.html">scoord3d</a></li><li><a href="segment.html">segment</a></li><li><a href="utils.html">utils</a></li><li><a href="viewer.html">viewer</a></li></ul><h3>Classes</h3><ul><li><a href="annotation.AnnotationGroup.html">AnnotationGroup</a></li><li><a href="color.PaletteColorLookupTable.html">PaletteColorLookupTable</a></li><li><a href="mapping.ParameterMapping.html">ParameterMapping</a></li><li><a href="mapping.Transformation.html">Transformation</a></li><li><a href="metadata.Comprehensive3DSR.html">Comprehensive3DSR</a></li><li><a href="metadata.MicroscopyBulkSimpleAnnotations.html">MicroscopyBulkSimpleAnnotations</a></li><li><a href="metadata.ParametricMap.html">ParametricMap</a></li><li><a href="metadata.Segmentation.html">Segmentation</a></li><li><a href="metadata.SOPClass.html">SOPClass</a></li><li><a href="metadata.VLWholeSlideMicroscopyImage.html">VLWholeSlideMicroscopyImage</a></li><li><a href="module.exports_module.exports.html">exports</a></li><li><a href="opticalPath.OpticalPath.html">OpticalPath</a></li><li><a href="roi.ROI.html">ROI</a></li><li><a href="scoord3d.Ellipse.html">Ellipse</a></li><li><a href="scoord3d.Ellipsoid.html">Ellipsoid</a></li><li><a href="scoord3d.Multipoint.html">Multipoint</a></li><li><a href="scoord3d.Point.html">Point</a></li><li><a href="scoord3d.Polygon.html">Polygon</a></li><li><a href="scoord3d.Polyline.html">Polyline</a></li><li><a href="scoord3d.Scoord3D.html">Scoord3D</a></li><li><a href="segment.Segment.html">Segment</a></li><li><a href="viewer.LabelImageViewer.html">LabelImageViewer</a></li><li><a href="viewer.OverviewImageViewer.html">OverviewImageViewer</a></li><li><a href="viewer.VolumeImageViewer.html">VolumeImageViewer</a></li></ul><h3>Global</h3><ul><li><a href="global.html#addTask">addTask</a></li><li><a href="global.html#cancelTask">cancelTask</a></li><li><a href="global.html#decode">decode</a></li><li><a href="global.html#getStatistics">getStatistics</a></li><li><a href="global.html#handleMessageFromWorker">handleMessageFromWorker</a></li><li><a href="global.html#initialize">initialize</a></li><li><a href="global.html#loadWebWorkerTask">loadWebWorkerTask</a></li><li><a href="global.html#setTaskPriority">setTaskPriority</a></li><li><a href="global.html#spawnWebWorker">spawnWebWorker</a></li><li><a href="global.html#startTaskOnWebWorker">startTaskOnWebWorker</a></li><li><a href="global.html#terminateAllWebWorkers">terminateAllWebWorkers</a></li><li><a href="global.html#transform">transform</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.10</a> on Thu Sep 29 2022 16:54:54 GMT-0400 (Eastern Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>