Last active
June 30, 2022 23:08
-
-
Save dfkaye/a469369646401208a2cb941cf7127756 to your computer and use it in GitHub Desktop.
self-serialize a command interface as an embedded worker; examples with object.prototype and class inheritance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 18 june 2022 | |
// self-serialize to a worker | |
// 21 june 2022 | |
// self-serialize a command interface as an embedded worker | |
// 30 June 2022 | |
// - slight cosmetic changes to prototype version | |
// - class implementation added (below) | |
// The idea takes less than 25 words to describe, but is still an | |
// extremely sketchy one. | |
// Define an object that serializes itself as a worker, then any | |
// command object can extend it. | |
// This is the prototype based version which does **not** demonstrate inheritance. | |
function Test() { | |
return Test.create(); | |
} | |
// commands | |
Test.prototype.pause = function (m) { | |
console.log(m, "pausing"); | |
return "paused"; | |
}; | |
Test.prototype.resume = function (m) { | |
console.log(m, "resuming"); | |
return "resumed"; | |
}; | |
// static factory | |
Test.create = function () { | |
console.log("create"); | |
var base = Test.prototype; | |
var self = Object.create(base); | |
// map functions as strings | |
for (var k in self) { | |
if (typeof self[k] == "function") { | |
self[k] = self[k].toString(); | |
} | |
} | |
// create worker script | |
var script = ` | |
self.actions = ${ JSON.stringify(self) }; | |
Object.keys(actions).forEach(function (k, F) { | |
F = Function("actions", "return " + actions[k] + ".bind(actions)"); | |
actions[k] = F(actions); | |
}); | |
self.onmessage = function (request) { | |
var action = request.data.action; | |
console.log("action:", action); | |
var response = action in actions && actions[action]("should " + action); | |
if (response) { | |
postMessage(response); | |
} | |
}; | |
`; | |
// console.log( script ) | |
// create blob | |
// create url | |
// create worker | |
var blob = new Blob([script], {type: 'text/javascript'}); | |
var url = window.URL.createObjectURL(blob); | |
var worker = new Worker(url); | |
// return control { pause => worker.pause, resume => worker.pause } | |
var api = { | |
onmessage: function (response) { | |
console.log("done", response); | |
} | |
}; | |
// map functions as commands to the worker | |
Object.keys(self).forEach(function (k) { | |
if (typeof base[k] == "function") { | |
api[k] = function() { | |
worker.postMessage({ action: k }); | |
}; | |
} | |
}); | |
worker.onmessage = function (response) { | |
api.onmessage(response.data); | |
}; | |
return api; | |
}; | |
/* test it out */ | |
var a = Test(); | |
a.pause(); | |
a.resume(); | |
// create | |
// action: pause | |
// should pause pausing | |
// action: resume | |
// should resume resuming | |
// done paused | |
// done resumed | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 18 june 2022 | |
// self-serialize to a worker | |
// 21 june 2022 | |
// self-serialize a command interface as an embedded worker | |
// 30 June 2022 | |
// - slight cosmetic changes to prototype version | |
// - class implementation added (below) | |
// The idea takes less than 25 words to describe, but is still an | |
// extremely sketchy one. | |
// Define an object that serializes itself as a worker, then any | |
// command object can extend it. | |
// This is the class based version which **does** demonstrate inheritance. | |
class Serialize { | |
constructor() { | |
return Serialize.create(this); | |
} | |
static create(self) { | |
console.log("create"); | |
var base = self.constructor.prototype | |
// map functions as strings | |
// Two reasons classes are terrible: | |
// 1. class prototype methods are **not** for...in enumerable | |
Object.getOwnPropertyNames(base).forEach(k => { | |
if (typeof self[k] == "function" && k != "constructor") { | |
var fs = self[k].toString().trim(); | |
// 2. prefix "function " to methods defined with shorthand (pause() {...}) | |
self[k] = /^function/.test(fs) | |
? fs | |
: "function " + fs; | |
} | |
}); | |
// create worker script | |
var script = ` | |
self.actions = ${ JSON.stringify( self ) }; | |
Object.keys(actions).forEach(function (k, F) { | |
F = Function("actions", "return " + actions[k] + ".bind(actions)"); | |
actions[k] = F(actions); | |
}); | |
self.onmessage = function (request) { | |
var action = request.data.action; | |
console.log("action:", action); | |
var response = action in actions && actions[action]("should " + action); | |
if (response) { | |
postMessage(response); | |
} | |
}; | |
`; | |
// console.log( script ) | |
// create blob | |
// create url | |
// create worker | |
var blob = new Blob([script], {type: 'text/javascript'}); | |
var url = window.URL.createObjectURL(blob); | |
var worker = new Worker(url); | |
// return control { pause => worker.pause, resume => worker.pause } | |
var api = { | |
onmessage: function (response) { | |
console.log("done", response); | |
} | |
}; | |
// map functions as commands to the worker | |
// assign action function to api if the key on self is a function on the prototype. | |
Object.keys(self).forEach(function (k) { | |
if (typeof base[k] == "function") { | |
api[k] = function () { | |
worker.postMessage({ action: k }); | |
}; | |
} | |
}); | |
worker.onmessage = function (response) { | |
api.onmessage(response.data); | |
}; | |
return api; | |
} | |
} | |
class Test extends Serialize { | |
constructor() { | |
return super(); | |
} | |
pause(m) { | |
console.log(m, "pausing"); | |
return "paused" | |
} | |
resume(m) { | |
console.log(m, "resuming"); | |
return "resumed" | |
} | |
} | |
/** test it out **/ | |
var w = new Test(); | |
w.pause(); | |
w.resume(); | |
// create | |
// action: pause | |
// should pause pausing | |
// action: resume | |
// should resume resuming | |
// done paused | |
// done resumed |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment