Как передать данные события со сцены в родительский контекст, не разбирая и не восстанавливая их?
Рассмотрим следующий код:
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 Exception 25
Если я просто рассылаю свойства, такие как ev.x и ev.y, они просто выдаются. Я также могу восстановить объект из его свойств перед отправкой, и он проходит нормально.
Как я могу отправить объект события без изменений в родительский контекст, не деконструируя-> реконструируя его? И, кстати, почему бонсай работает именно так?
1 ответ
Здорово, что вы спросили, почему мы делаем разделение таким образом. Просто просмотрел документацию по 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({...});
Основная причина помещения основного выполнения кода в работника состоит в том, что мы не хотим, чтобы какие-либо вычисления блокировали рендеринг "потока", чтобы мы могли получить более плавные анимации (если код выполняется в iFrame, рендеринг + выполнение кода будет происходить в том же потоке, и оно не будет таким же беглым, как с рабочим). Другое преимущество выполнения JS-кода на рабочем месте состоит в том, что мы не полагаемся на DOM, а также можем взять тот же JS-код и выполнить его в другой среде JS, такой как Rhino или NodeJS (вот пример кода, как вы может выполнить BonsaiJS на узле и отправить сообщения рендеринга в браузер через SocketIO: https://github.com/uxebu/bonsai-server).