Как передать большие объекты с помощью postMessage веб-работника?

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

Вопрос в том, как преобразовать произвольный объект большого размера (30 МБ) в передаваемый объект и передать его в качестве аргумента в postmessage. Из того, что я понимаю, я могу преобразовать мой массив в строку json, а затем преобразовать строку json в необработанные байтовые данные и сохранить их внутри объекта массива. Однако, это, кажется, побеждает цель быстрой передачи.

Может ли кто-нибудь просветить меня, чтобы передать объект в качестве передаваемого объекта или, если это вообще возможно?

Заранее спасибо!

2 ответа

Это заблуждение вполне повторяется здесь. Вы представляете, что можно написать какой-то быстрый код JavaScript, чтобы преобразовать ваш большой объект в передаваемый. Но на самом деле, любой код преобразования, который вы пишете, побеждает цель, как вы и сказали. И чем сложнее данные, тем больше скорости вы теряете.

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

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

В качестве последней заметки я написал библиотеку на основе прототипов, которая преобразует объекты javascript в ArrayBuffer и обратно. Это медленнее, особенно для данных типа JSON. Это преимущества (и преимущества любого подобного кода, который вы пишете):

  1. Вы можете определить пользовательские преобразования объекта
  2. Вы можете использовать наследование (например, отправка ваших собственных типов, таких как Foo)

Код для передачи JSON-подобного объекта

Если ваши данные похожи на JSON, просто придерживайтесь структурированного клона и не передавайте. Если вы мне не доверяете, проверьте это с помощью этого кода. Вы увидите, что это медленнее, чем обычно postMessage,

var object = {dd:"ddd", sub:{xx:"dd"}, num:666};
var string = JSON.stringify(object);
var uint8_array = new TextEncoder(document.characterSet.toLowerCase()).encode(string);
var array_buffer = uint8_array.buffer;
// now transfer array buffer
worker.postMessage(array_buffer, [array_buffer])

Обратное преобразование, учитывая, что у вас есть некоторые ArrayBuffer:

// Let me just generate some array buffer for the simulation
var array_buffer = new Uint8Array([123,34,100,100,34,58,34,100,100,100,34,44,34,115,117,98,34,58,123,34,120,120,34,58,34,100,100,34,125,44,34,110,117,109,34,58,54,54,54,125]).buffer;
// Now to the decoding
var decoder = new TextDecoder("utf-8");
var view = new DataView(array_buffer, 0, array_buffer.byteLength);
var string = decoder.decode(view);
var object = JSON.parse(string);

Должен был посмотреть ответ Томаса ранее.

Доказательство, хотя не совсем так, как предложил Томас.

Версия А

Версия Б

Я вручную преобразовал в строковый json-объект в Uint8Array следующим образом:

function stringToUintArray(message) {
  var encoded = self.btoa(message);
  var uintArray = Array.prototype.slice.call(encoded).map(ch => ch.charCodeAt(0));
  var uarray = new Uint8Array(uintArray);
  return uarray;
}

и перевел это так от веб-работника в основной поток:

console.time('generate');
    var result = generate(params.low, params.high, params.interval, params.size);
    var uarr = stringToUintArray(JSON.stringify(result));
    console.timeEnd('generate');
    self.postMessage(uarr.buffer, [uarr.buffer]);

и в основной теме я сделал что-то вроде этого:

var uarr = new Uint8Array(e.data);
var json = UintArrayToString(uarr);
var result = JSON.parse(json);

введите описание изображения здесь

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