-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathpyodide-worker.js
117 lines (105 loc) · 3.34 KB
/
pyodide-worker.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Relative paths are fine here
/**
* @typedef { import("../src/cas/pyodide-cas").WorkerMessage } WorkerMessage
*/
/**
* @typedef { import("../src/cas/pyodide-cas").WorkerResponse } WorkerResponse
*/
/**
* QuantumSheet Loading Time
Improvements
- Upgrade to Pyodide 0.18.x (fpcast & smoler)
- Preload
- CDN (compressed) with fallback to github pages pyodide
Current Loading Time (without any of the improvements ^)
Everything in cache, just reload: 2.84s, 2.95s, 2.72s, 2.90s
Disable cache: 17.66s, 17.19s, 13.79s, 18.70s
36.20 MB / 23.33 MB transferred
*/
globalThis.importScripts('./pyodide/pyodide.js')
let pyodide = undefined
const loadPyodide = globalThis
.loadPyodide({
indexURL: './pyodide/',
fullStdLib: false, // Don't load the full standard library, hopefully this doesn't cause any issues
})
.then(async (pyodide) => {
const loadPackagePromise = pyodide.loadPackage(['mpmath', 'sympy'])
const mathjsonPy = await fetch('./mathjson.py').then((v) => v.text())
await loadPackagePromise
pyodide.runPython('import sys\nsys.setrecursionlimit(999)\nimport sympy')
pyodide.runPython(mathjsonPy)
return pyodide
})
.catch((error) => console.error(error))
if (globalThis.SharedWorkerGlobalScope) {
globalThis.onconnect = (/**@type {MessageEvent} */ event) => {
const messagePort = event.ports[0]
messagePort.onmessage = function (event) {
messagePort.postMessage(messageHandler(event))
}
loadPyodide.then((v) => {
messagePort.postMessage({ type: 'initialized' })
pyodide = v
})
}
} else if (globalThis.WorkerGlobalScope) {
globalThis.onmessage = function (event) {
globalThis.postMessage(messageHandler(event))
}
loadPyodide.then((v) => {
globalThis.postMessage({ type: 'initialized' })
pyodide = v
})
} else {
console.error('Please use this script in a web worker or shared worker')
}
/**
*
* @param {string[]} symbols
* @param {string} command
*/
function wrapSympyCommand(symbols, command) {
const argumentNames = symbols.join(',')
const argumentValues = symbols.map((v) => `sympy.Symbol('${v}')`).join(',')
const pyCommand = `MathJsonPrinter().doprint((lambda ${argumentNames}: ${command})(${argumentValues}))`
return pyCommand
}
/**
*
* @param {MessageEvent} event
* @returns {WorkerResponse}
*/
function messageHandler(event) {
/** @type {WorkerMessage} */
const message = event.data
if (!message) return
try {
let pyodideResult = undefined
if (message.type == 'python') {
pyodideResult = pyodide.runPython(message.command)
} else if (message.type == 'expression') {
pyodideResult = pyodide.runPython(wrapSympyCommand(message.symbols, message.command))
} else {
throw new Error('Unknown command type', message)
}
if (pyodideResult?.destroy) {
console.warn('Pyodide returned a proxy', pyodideResult.toString()) // Internally calls repr()
console.warn(Reflect.ownKeys(pyodideResult)) // Lists all properties and methods
//console.warn(pyodideResult.__doc__) // Shows the documentation string
pyodideResult.destroy()
pyodideResult = undefined
}
return {
type: 'result',
id: message.id,
data: pyodideResult,
}
} catch (e) {
return {
type: 'error',
id: message.id,
message: `Command ${message.command} resulted in an error ${e.message}`,
}
}
}