Worker'ы — внятная реализация многопоточности в JavaScript. На момент сейчас они имеют достаточное количество ограничений. Для ознакомления с ними (как worker'ами, так и ограничениями) можно прочитать эту статью от хабраюзера Antelle. Там же есть и ссылки на первоисточники информации для интересующихся.
Сегодня же мне довелось столкнуться другой задачей. А именно: с проблемой создания worker'а из js-файла с другого домена, что на данный момент запрещено его спецификацией.
История началась с создания небольшого расширения Google Chrome для Chess.com, которое использовало стороннюю библиотеку. К несчастью, оказалось, что эта библиотека работает только как worker.
Проблема заключается в том, что у самого Chrome есть определенные ограничения на получение файлов из контекста страницы. Он разрешает внедрение стороннего javascript-кода на страницу, но не более того. А это значит, что код из дополнения может получать worker на страницу только с того домена, на котором он выполнялся. То есть в моем случае: Chess.com. Конечно, можно было бы рассчитывать, что когда-нибудь я получу доступ к боевым серверам Chess.com, но мне бы хотелось, чтобы все заработало уже сегодня. Пришлось гуглить.
К счастью, статья с html5rocks помогла найти решение: создание inline worker'а через Blob. Подробности здесь. Если говорить кратко, то можно создать любую текстовую строку и запихать ее в так называемый Blob —наскальный рисунок модельный прототип сырого внешнего файла.
Например так (взято с html5rocks):
Здесь мы видим, что создается объект Blob, который в представлении браузера является «как-бы-файлом», и в него записывается исходный текст.
Но если мы можем создать из любого текста Blob, значит, можно загрузить любой текст с другого сайта, а потом запихнуть его в Blob?
Окей, давайте попробуем:
Работает. То есть, фактически, мы можем загрузить любой внешний файл на страницу и запустить его как worker, независимо от принадлежности файлов к одному или нескольким доменам. Нда, вот так день.
Напоследок замечу, что, несмотря на всю сенсационность заголовка, в принципе в этом трюке нет ничего удивительного. То же самое можно проделать и для однопоточного javascript-кода: загрузить его как текст и вызвать через eval. В этом случае остается непонятным лишь неспешное принятие решения о поддержке CORS в Web Workers.
Сегодня же мне довелось столкнуться другой задачей. А именно: с проблемой создания worker'а из js-файла с другого домена, что на данный момент запрещено его спецификацией.
История началась с создания небольшого расширения Google Chrome для Chess.com, которое использовало стороннюю библиотеку. К несчастью, оказалось, что эта библиотека работает только как worker.
Проблема заключается в том, что у самого Chrome есть определенные ограничения на получение файлов из контекста страницы. Он разрешает внедрение стороннего javascript-кода на страницу, но не более того. А это значит, что код из дополнения может получать worker на страницу только с того домена, на котором он выполнялся. То есть в моем случае: Chess.com. Конечно, можно было бы рассчитывать, что когда-нибудь я получу доступ к боевым серверам Chess.com, но мне бы хотелось, чтобы все заработало уже сегодня. Пришлось гуглить.
К счастью, статья с html5rocks помогла найти решение: создание inline worker'а через Blob. Подробности здесь. Если говорить кратко, то можно создать любую текстовую строку и запихать ее в так называемый Blob —
Например так (взято с html5rocks):
var blob = new Blob([
"onmessage = function(e) { postMessage('msg from worker'); }"]);
// Obtain a blob URL reference to our worker 'file'.
var blobURL = window.URL.createObjectURL(blob);
var worker = new Worker(blobURL);
worker.onmessage = function(e) {
// e.data == 'msg from worker'
};
worker.postMessage(); // Start the worker.
Здесь мы видим, что создается объект Blob, который в представлении браузера является «как-бы-файлом», и в него записывается исходный текст.
Но если мы можем создать из любого текста Blob, значит, можно загрузить любой текст с другого сайта, а потом запихнуть его в Blob?
Окей, давайте попробуем:
$.get("https://example.com/js/worker.js", {},
function (workerCode) {
var blob = new Blob([workerCode], {type : 'javascript/worker'});
var worker = new Worker(window.URL.createObjectURL(blob));
}
);
Работает. То есть, фактически, мы можем загрузить любой внешний файл на страницу и запустить его как worker, независимо от принадлежности файлов к одному или нескольким доменам. Нда, вот так день.
Напоследок замечу, что, несмотря на всю сенсационность заголовка, в принципе в этом трюке нет ничего удивительного. То же самое можно проделать и для однопоточного javascript-кода: загрузить его как текст и вызвать через eval. В этом случае остается непонятным лишь неспешное принятие решения о поддержке CORS в Web Workers.
BeLove
Но чтобы загрузить файл (тот же внешний js с worker'ом) и получить доступ к телу ответа, нам нужен CORS со стороны как раз домена, где находится worker. Так что не любой внешний файл.
UPD: А, речь же про расширение. Видимо с неограниченными запросами ко всем доменам. Может, стоит уточнить тему топика, что речь именно про расширения, да еще и с неприлично большими правами.
artyfarty
Ну, скачать-то можно и без корса по JSONP
BeLove
Но для этого нам снова нужен доступ к серверу, где хранится worker.
Взаимоисключения.
artyfarty
Изначальная проблема, из-за которой требуется CORS в том, что даже имея внешний сервер (провайдер), современный JS затрудняет получение чего-бы то ни было оттуда с сайта, на котором у нас виджет или расширение (консьюмер). То есть вот у нас есть внешний сервер с ресурсами и апи, но фигушки наш виджет, работая в домене консьюмера (хоть и загруженный с нашего сервера) сможет сделать туда обычный XHR, только корс (что геморройно) или жсонп (что с ограничениями). А статья о том, что воркер мол вообще тривиально не создать на консьюмере с урла провайдера — только через вышеприведенный фокус.
BeLove
Я прекрасно понимаю, зачем нужен CORS.
Как и трюк, который был приведен в статье. Вопросов к этому не было.