Передача объектов веб-работнику - PullRequest
49 голосов
/ 09 октября 2011

Я пытаюсь передать объект веб-работнику через функцию postMessage.
Этот объект представляет собой квадрат, имеющий несколько функций для рисования на холсте и некоторых других вещах. Веб-работник должен вернуть массив этих объектов.
Проблема в том, что когда я вызываю функцию postMessage с этим объектом, я получаю эту ошибку:

Uncaught Error: DATA_CLONE_ERR: DOM Exception 25

Я получаю и отправку объекта рабочему, и наоборот.
Я думаю, что ошибка в том, что javascript должен сериализовать объект, но не может сделать это, потому что у объекта есть встроенные функции.

У кого-нибудь когда-нибудь была подобная проблема? Вы знаете какой-нибудь обходной путь к этому?
Заранее спасибо.

Ответы [ 7 ]

49 голосов
/ 09 октября 2011

Существует несколько причин, по которым указанная вами ошибка могла быть выдана, причины перечислены здесь .

При отправке объектов веб-работникам объект сериализуется, ипозже десериализуется в веб-работнике, если объект является сериализуемым объектом.

Это означает, что методы для объектов, которые вы отправляете веб-работнику, не могут быть переданы веб-работнику (вызывая ошибку, с которой вы столкнулись), и вам нужно будет предоставить необходимыеметоды / функции для объектов на стороне веб-работника среды и убедитесь, что они не являются частью объекта, который передается веб-работнику (-ям).

12 голосов
/ 19 января 2012

Поскольку вы подозревали, что объекты с функциями не могут быть опубликованы. То же самое касается объектов с рекурсивными ссылками, но в последнее время это изменилось в некоторых браузерах. Вместо того, чтобы рисковать делать ручную и дорогостоящую избыточную сериализацию для каждого сообщения, вы можете выполнить тест в начале вашего сценария, чтобы определить, какие функции использовать для отправки / получения данных.

У меня была та же проблема, и я решил ее, переместив почти весь код в рабочий и просто сохранив средство рендеринга (оборачивая 2d контекстный рендер) в основном потоке. На рабочем месте я сериализую различные вызовы отрисовки, предназначенные для холста, в виде чисел в (типизированном) массиве. Затем этот массив публикуется в главном потоке.

Так, например, когда я хочу нарисовать изображение, я вызываю метод drawImage() на своем экземпляре визуализатора работника в работнике. Вызов переводится в нечто вроде [13,1,50,40], что соответствует enum метода draw, уникальному идентификатору изображения и его координатам xy. Несколько вызовов буферизуются и помещаются в один массив. В конце цикла обновления массив размещается в главном потоке. Принимающий экземпляр основного средства визуализации анализирует массив и выполняет соответствующие вызовы отрисовки.

6 голосов
/ 20 апреля 2014

Я недавно столкнулся с этой же проблемой при использовании веб-работников.Все, что я передавал своему работнику, сохраняло все его свойства, но загадочным образом теряло все свои методы.

Вам придется определить методы в самом скрипте веб-работника.Один из обходных путей - importScripts определение класса и ручная установка свойства __proto__ всего, что вы получаете.В моем случае я хотел передать объект grid, определенный в grid.js (да, я работал на 2048), и сделал это так:

importScripts('grid.js')

onMessage = function(e) {
  e.data.grid.__proto__ = Grid.prototype;
  ...
}
4 голосов
/ 04 сентября 2012

Настоящая проблема с объектами и веб-работниками заключается в методах этих объектов. У объекта не должно быть методов, только свойства.

Ex:

var myClass = function(){
    this.a = 5;
    this.myMethod = function(){}
}
var notParseableObject = new myClass();


var myClass2 = function(){
    this.a = 5;
}
var parseableObject = new myClass2();

Первый не будет работать (с упомянутым сообщением об ошибке) с postMessage, а второй будет работать.

3 голосов
/ 10 июля 2017

Когда вы передаете данные веб-работнику, копия данных создается с помощью алгоритма структурированного клона . Это указано в HTML5 (см. § 2.9: Безопасная передача структурированных данных ).

MDN имеет обзор поддерживаемых типов . Поскольку функции не поддерживаются, попытка клонировать объекты, содержащие функции, приведет к исключению DATA_CLONE_ERR.

Что делать, если у вас есть объект с функциями?

  • Если функции не актуальны, попробуйте создать новый объект, который содержит только данные, которые вы хотите перенести. Пока вы используете только поддерживаемые типы, отправка должна работать. Использование JSON.stringify и JSON.parse также может использоваться в качестве обходного пути, так как stringify игнорирует функции.

  • Если функции актуальны, переносного способа не существует. Есть попытки использовать комбинацию toString и eval (например, используемую библиотекой jsonfs ), но это не будет работать во всех случаев. Например, он сломается, если ваша функция будет нативным кодом. Также закрытие проблематично.

1 голос
/ 30 июля 2013

взгляните на плагин vkThread

http://www.eslinstructor.net/vkthread/

может передавать функцию работнику, включая функцию с контекстом (метод объекта). Он также может передавать функции с зависимостями, анонимными функциями и лямбдами.

- Вадим

0 голосов
/ 10 июля 2018

Некоторые типы объектов, такие как ArrayBuffer и ImageBitmap, которые имеют реализацию интерфейса Transferable и могут передаваться без копирования Object.

Это очень полезно в контексте Canvas + Web работника, потому что вы можете сэкономить время копирования данных между потоками.

...