Public
Edited
Apr 9
1 fork
Importers
57 stars
Also listed in…
Algorithms
Hello
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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more