У меня есть работник, который разделяет SharedArrayBuffer с «основным потоком». Для корректной работы я должен убедиться, что у работника есть доступ к SAB, прежде чем основной поток получит к нему доступ. (РЕДАКТИРОВАТЬ: код, создающий работника, должен быть в отдельной функции (EDIT2: который возвращает массив, указывающий на SAB).) (Возможно, уже это невозможно, вы мне скажете).
Исходный код выглядит следующим образом:
function init() {
var code = `onmessage = function(event) {
console.log('starting');
var buffer=event.data;
var arr = new Uint32Array(buffer);// I need to have this done before accessing the buffer again from the main
//some other code, manipulating the array
}`
var buffer = new SharedArrayBuffer(BUFFER_ELEMENT_SIZE);
var blob = new Blob([code], { "type": 'application/javascript' });
var url = window.URL || window.webkitURL;
var blobUrl = url.createObjectURL(blob);
var counter = new Worker(blobUrl);
counter.postMessage(buffer);
let res = new Uint32Array(buffer);
return res;
}
function test (){
let array = init();
console.log('main');
//accessing the SAB again
};
Рабочий код всегда выполняется после test()
, консоль всегда показывает main
, затем starting
.
Использование тайм-аутов делает нет помощи. Рассмотрим следующий код для test
:
function test (){
let array = [];
console.log('main');
setTimeout(function(){
array = initSAB();
},0);
setTimeout(function(){
console.log('main');
//accessing the SAB again
},0);
console.log('end');
};
Сначала на консоли выводится end
, затем main
, затем starting
.
Однако при назначении буфера глобальный массив вне функции test () выполняет работу, даже без тайм-аутов.
У меня следующие вопросы:
- , почему рабочий не запускается сразу после сообщения отправить (= получил?). AFAIK, рабочие имеют свою собственную очередь событий, поэтому они не должны полагаться на то, что основной стек становится пустым?
- Существует ли спецификация, детализирующая , когда работник начинает работать после отправки сообщения?
- Есть ли способ убедиться, что работник начал работу, прежде чем снова получить доступ к SAB без использования глобальных переменных? (Можно использовать занятое ожидание, но я опасаюсь ...) Вероятно, нет никакого пути, но я хочу быть уверенным.
Редактировать
Точнее:
- В полностью параллельном сценарии Worker сможет обработать сообщение сразу после его публикации. Это явно не тот случай.
- Большинство API браузеров (а Worker - такой API) используют очередь обратного вызова для обработки вызовов к API. Но если это применимо, сообщение будет отправлено / обработано до того, как будут выполнены обратные вызовы тайм-аута.
- К go даже дальше: Если я попытаюсь заняться ожиданием после postMessage путем чтения из SAB, пока оно не изменит одно значение заблокирует программу бесконечно . Для меня это означает , что Браузер не отправляет сообщение, пока стек вызовов не станет пустым Насколько я знаю, это поведение не задокументировано, и я не могу это объяснить.
Подводя итог: Я хочу знать, как браузер определяет, когда отправлять сообщение и обрабатывать его работником, если вызов postMessage находится внутри функции. Я уже нашел обходной путь (глобальные переменные), поэтому меня больше интересует, как это работает за кулисами. Но если кто-то может показать мне рабочий пример, я возьму его.
РЕДАКТИРОВАТЬ 2:
Код, использующий глобальную переменную (код, который работает нормально), выглядит следующим образом
function init() {
//Unchanged
}
var array = init(); //global
function test (){
console.log('main');
//accessing the SAB again
};
Он печатает starting
, затем main
на консоли.
Что также стоит отметить: Если я отлаживаю код с помощью Firefox Browser ( Chrome не проверено) Я получаю желаемый результат без глобальной переменной (starting
до main
) Может кто-нибудь объяснить?