Public
Edited
Apr 9
1 fork
Importers
57 stars
Insert cell
Insert cell
// read results as they are arriving
Generators.queue(worker(blah, 100))
Insert cell
// don't pause between yields
Generators.observe(worker(blah, 100000))
Insert cell
// pass several named arguments
Generators.queue(worker(who, { n: 100, k: 21 }))
Insert cell
// retrieve a simple result
Generators.queue(worker(meh))
Insert cell
// anonymous function
Generators.queue(worker(() => "foo"))
Insert cell
// Async generator
Generators.queue(
worker(async function* () {
for (let i = 0; i < 100; i++) {
yield i;
}
})
)
Insert cell
// Use ES6 modules in the preamble
Generators.queue(
worker(
function () {
return dthree.range(0, 10);
},
{ type: "module" },
`import * as dthree from "https://cdn.jsdelivr.net/npm/d3@7/+esm";`
)
)
Insert cell
// a fake `dthree` that we don't use in the main thread, but avoids a runtime error with the function
dthree = null
Insert cell
// async function
observeWorker`return await fetch("https://d3js.org/").then(d => d.text()).then(text => text.length);`
Insert cell
webWorker = (method) =>
function (f, ...vars) {
let t = f[0];
const args = {};
for (let i = 0; i < vars.length; i++) {
t = `${t}${
typeof vars[i] === "function"
? function_stringify(vars[i])
: ((args[`a${i}`] = vars[i]), `data.a${i}`)
}${f[i + 1]}`;
}
// auto-detect async functions
const _async = t.match(/\b(await|async)\b/) ? "async " : "";

return Generators[method](
worker(
{
toString: () => `${_async}function main(data) {\n${t}\n;;;\n}`,
name: "main"
},
args
)
);
}
Insert cell
queueWorker = webWorker("queue")
Insert cell
observeWorker = webWorker("observe")
Insert cell
worker = function (f, e, preamble, transferList) {
const b = new Blob([workertext(f, preamble)], { type: "text/javascript" });
return function (notify) {
const url = URL.createObjectURL(b);

const worker = new Worker(url, { type: (e && e?.type) || "classic" });
worker.addEventListener("message", (r) => notify(r.data));
worker.postMessage(e, transferList);
return () => {
worker.terminate();
URL.revokeObjectURL(url);
};
};
}
Insert cell
// just like Observable, we don't want to iterate on arrays
// so we check if our iterator has a method .next()
function workertext(f, preamble = "") {
return `
${preamble}

function isIterable(obj) {
return (
typeof obj[Symbol.iterator] === "function" &&
typeof obj["next"] == "function"
);
}

const __run__ = ${typeof f === "function" ? function_stringify(f) : f};

self.onmessage = async function(e) {
const t0 = performance.now();
let result = await __run__(e.data);

const postHelper = p =>
postMessage(
typeof p !== "object" || !Object.isExtensible(p) ?
p :
Object.assign(p, {_time: performance.now() - t0})
);
if (typeof result[Symbol.asyncIterator] === "function") {
for await (const p of result) {
postHelper(p);
}
close();
}
if (typeof result !== "undefined") {
if (!isIterable(result)) result = [result];
for (const p of result) {
postHelper(p);
}
close();
}

}`;
}
Insert cell
// On iOS, [generator].toString() doesn't give "function*" but "function". Fix this.
function function_stringify(f) {
let g = f.toString();
if (f.prototype && f.prototype.toString() === "[object Generator]")
g = g.replace(/function\*?/, "function*");
return g;
}
Insert cell
function* blah(n) {
let sum = 0;
while (n-- > 0) yield (sum += n);
}
Insert cell
function* who({ n, k }) {
let sum = 0;
while (n-- > 0) yield k * (sum += n);
}
Insert cell
function meh() {
let sum = 0,
n = 100;
while (n-- > 0) {
sum += n;
}
return sum;
}
Insert cell
Insert cell
Generators.queue(worker(d => d ** 2, 10))
Insert cell
Insert cell
Generators.queue(
worker(
delaunay,
[0, 0, 1, 2.1, 4, 3],
`
importScripts("https://unpkg.com/d3-delaunay");
const de = d3;
`
)
)
Insert cell
Type Markdown, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Generators.queue(
worker(
delaunay,
Object.assign([0, 0, 1, 2.1, 4, 3], {type: "module"}),
`
import * as d3 from "https://cdn.jsdelivr.net/npm/d3-delaunay/+esm";
const de = d3;
`
)
)
Insert cell
function delaunay(data) {
return new de.Delaunay(Float32Array.from(data));
}
Insert cell
// a fake `de` that we don't use in the main thread, but avoids a runtime error with the function
de = "🤯"
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more