@jspm/core
Version:
This package contains the core libraries used in jspm 2.
140 lines (121 loc) • 4.24 kB
JavaScript
import { EventEmitter, once } from './events.js';
function unimplemented(name) {
throw new Error(
`Node.js worker_threads ${name} is not currently supported by JSPM core in Deno`,
);
}
let environmentData = new Map();
let threads = 0;
const kHandle = Symbol('kHandle');
export class Worker extends EventEmitter {
resourceLimits = {
maxYoungGenerationSizeMb: -1,
maxOldGenerationSizeMb: -1,
codeRangeSizeMb: -1,
stackSizeMb: 4,
};
constructor(specifier, options) {
super();
if (options?.eval === true) {
specifier = URL.createObjectURL(new Blob([specifier], { type: 'application/javascript' }));
}
const handle = this[kHandle] = new globalThis.Worker(specifier, {
...(options || {}),
type: 'module',
});
handle.addEventListener('error', (event) => this.emit('error', event.error || event.message));
handle.addEventListener('messageerror', (event) => this.emit('messageerror', event.data));
handle.addEventListener('message', (event) => this.emit('message', event.data));
handle.postMessage({
environmentData,
threadId: (this.threadId = ++threads),
workerData: options?.workerData,
}, options?.transferList);
this.postMessage = handle.postMessage.bind(handle);
this.emit('online');
}
terminate() {
this[kHandle].terminate();
this.emit('exit', 0);
}
getHeapSnapshot = () => unimplemented('Worker#getHeapsnapshot');
// fake performance
performance = globalThis.performance;
}
export const isMainThread = typeof WorkerGlobalScope === 'undefined' || self instanceof WorkerGlobalScope === false;
// fake resourceLimits
export const resourceLimits = isMainThread ? {} : {
maxYoungGenerationSizeMb: 48,
maxOldGenerationSizeMb: 2048,
codeRangeSizeMb: 0,
stackSizeMb: 4,
};
let threadId = 0;
let workerData = null;
let parentPort = null;
if (!isMainThread) {
const listeners = new WeakMap();
parentPort = self;
parentPort.off = parentPort.removeListener = function (name, listener) {
this.removeEventListener(name, listeners.get(listener));
listeners.delete(listener);
return this;
};
parentPort.on = parentPort.addListener = function (name, listener) {
const _listener = (ev) => listener(ev.data);
listeners.set(listener, _listener);
this.addEventListener(name, _listener);
return this;
};
parentPort.once = function (name, listener) {
const _listener = (ev) => listener(ev.data);
listeners.set(listener, _listener);
this.addEventListener(name, _listener);
return this;
};
// mocks
parentPort.setMaxListeners = () => {};
parentPort.getMaxListeners = () => Infinity;
parentPort.eventNames = () => [];
parentPort.listenerCount = () => 0;
parentPort.emit = () => notImplemented();
parentPort.removeAllListeners = () => notImplemented();
([{ threadId, workerData, environmentData }] = await once(parentPort, 'message'));
// alias
parentPort.addEventListener('offline', () => parentPort.emit('close'));
}
export function getEnvironmentData(key) {
return environmentData.get(key);
}
export function setEnvironmentData(key, value) {
if (value === undefined) {
environmentData.delete(key);
} else {
environmentData.set(key, value);
}
}
export const markAsUntransferable = () => unimplemented('markAsUntransferable');
export const moveMessagePortToContext = () => unimplemented('moveMessagePortToContext');
export const receiveMessageOnPort = () => unimplemented('receiveMessageOnPort');
export const MessagePort = globalThis.MessagePort;
export const MessageChannel = globalThis.MessageChannel;
export const BroadcastChannel = globalThis.BroadcastChannel;
export const SHARE_ENV = Symbol.for('nodejs.worker_threads.SHARE_ENV');
export { parentPort, threadId, workerData }
export default {
markAsUntransferable,
moveMessagePortToContext,
receiveMessageOnPort,
MessagePort,
MessageChannel,
BroadcastChannel,
Worker,
getEnvironmentData,
setEnvironmentData,
SHARE_ENV,
threadId,
workerData,
resourceLimits,
parentPort,
isMainThread,
}