太好了,你问我们为什么要这样分离。刚刚浏览了 BonsaiJS 文档并意识到我们没有明确说明为什么我们将渲染与执行线程分开。
BonsaiJS 代码主要在工作人员中执行(如果工作人员不可用,则回退到 iframe)并用于postMessage
与创建工作人员的上下文进行通信。被DATA_CLONE_ERR: DOM Exception 25
引发是因为 DOM 事件对象不能被postMessage
. 为了解决您的问题,您可以创建一个简单的函数,该函数删除应该传递的对象的所有嵌套对象/函数:
window.stage = bonsai.run(document.getElementById('stage'), {
code: function() {
var circle;
var makeSerializable = function(obj) {
var ret = {}, val;
Object.keys(obj).forEach(function(key) {
val = obj[key];
if (typeof val != 'object' && typeof val != 'function') {
ret[key] = val;
};
});
return ret;
};
circle = new Circle(200, 200, 50);
circle.stroke('green', 2);
circle.addTo(stage);
circle.on('click', function(ev) {
stage.sendMessage('click', makeSerializable(ev));
});
},
width: 500,
height: 500
});
stage.on('load', function() {
console.log('loaded');
stage.on('message:click', function(ev) {
console.log('click', ev);
});
});
或者您可以强制 BonsaiJS 在 iFrame 中执行。然后你就可以访问 DOM 并且可以序列化任何对象(注意:见下文,为什么我不建议这样做):
window.stage = bonsai.setup({
runnerContext: bonsai.IframeRunnerContext
}).run({...});
将主要代码执行放到worker中的主要原因是,我们不希望任何计算阻塞渲染“线程”,这样我们可以获得更流畅的动画(如果代码在iFrame中执行,渲染+代码执行将发生在同一个线程中,并且不会像工作线程那样流畅)。在 worker 中执行 JS 代码的另一个好处是,我们不依赖 DOM,还可以获取相同的 JS 代码并在 Rhino 或 NodeJS 等不同的 JS 环境中执行它(这里有一些示例代码,你如何可以在节点上执行 BonsaiJS 并通过 SocketIO 将渲染消息发送到浏览器:https ://github.com/uxebu/bonsai-server )。