考虑以下代码:
window.stage = bonsai.run(document.getElementById('stage'), {
code: function() {
var circle;
circle = new Circle(200, 200, 50);
circle.stroke('green', 2);
circle.addTo(stage);
circle.on('click', function(ev) {
stage.sendMessage('click', ev);
});
},
width: 500,
height: 500
});
stage.on('load', function() {
console.log('loaded');
stage.on('message:click', function(ev) {
console.log('click', ev);
});
});
因此,点击圈子会出现错误: DATA_CLONE_ERR:DOM例外25
如果我发送像ev.x和ev.y这样的属性,它们会传出正常的结果。我也可以在发送之前从其属性重建对象,并且传递正常。
如何将事件对象完整地发送到父上下文而不解构 - >重建它?顺便说一句,盆景为什么会这样工作?
答案 0 :(得分:2)
很好,你已经问过为什么我们这样做了分离。刚刚浏览了BonsaiJS文档并意识到我们没有明确说出为什么我们将渲染与执行线程分开。
BonsaiJS代码主要在工作程序中执行(如果工作程序不可用,则返回iframe)并使用postMessage
与创建工作程序的上下文进行通信。引发DATA_CLONE_ERR: DOM Exception 25
是因为postMessage
无法序列化DOM事件对象。要解决您的问题,您可以创建一个简单的函数,它删除对象的所有嵌套对象/函数,应该传递:
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代码并在不同的JS环境中执行它,如Rhino或NodeJS(这里是一些示例代码,如何使用可以在节点上执行BonsaiJS并通过SocketIO将呈现消息发送到浏览器:https://github.com/uxebu/bonsai-server)。