Как передать данные события со сцены в родительский контекст, не разбирая и не восстанавливая их?

Рассмотрим следующий код:

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).

Другие вопросы по тегам