Использование Web-работников в Angular-приложении (сервисный работник кеширует доступ к данным в Angular-Cli)
Я хочу запустить функцию (в фоновом режиме) с помощью работника. Данные поступают из http-запроса. Я использую фиктивный расчет (e.data[0] * e.data[1] * xhrData.arr[3])
(заменяется функцией, возвращающей фактический результат алгоритма), как показано ниже:
var ajax = function() {
var prom = new Promise(function(resolve, reject){
if (!!XMLHttpRequest) {
var xhttp = new XMLHttpRequest();
xhttp.onload = function () {
if (this.readyState == 4 && this.status == 200) {
resolve(JSON.parse(this.responseText));
}
};
// Cache Logic - Will be adding logic to check cache
// if test.json is in cache.
// If it is then fetch res from cache
// There will be multiple XHR requests in parallel, not one
xhttp.open("GET", "test.json", true);
xhttp.send();
}
});
return prom;
}
async function test (e) {
var workerResult, xhrData;
try {
xhrData = await ajax();
workerResult = (e.data[0] * e.data[1] * xhrData.arr[3]);
postMessage({res: workerResult});
} catch(err) {
postMessage({err: 'Failed'});
}
}
onmessage = function (e) {
test(e);
};
Это отлично работает. Но это чистая реализация JS. Я планировал использовать для этого сервис (плюс совместно используемый работник), поэтому я создаю только одного работника для каждого углового приложения и не имею проблем с памятью. Это будет триггер от действия пользовательской кнопки отправки формы.
Мой вопрос:
Во-первых, мне интересно, могут ли это сделать сервисные работники в самом Angular, поскольку это также тип фонового рабочего потока.
Во-вторых, если это невозможно, могу ли я получить доступ к кешу сервисных работников из веб-работника? и возможно ли получить доступ к этому кешу рабочего сервиса. Как это должно быть сделано? Любая помощь приветствуется.
Обратите внимание, что я могу работать с сервисными работниками, и я могу кэшировать все статические активы с использованием сервисов угловых сервисов.
Обновить:
Мне удалось получить некоторую базовую идею о включении кэширования данных в угловом приложении, используя следующую конфигурацию, над которой я сейчас работаю.
{
"name": "someapi",
"urls": ["/someuri", "/users"],
"cacheConfig": {
"strategy": "freshness",
"maxSize": 20,
"maxAge": "1h",
"timeout": "5s"
}
}
Обновить:
Я был в состоянии получить это и работать в сыром, но это сработало. Добавлен ресурс, которому нужен XHR-запрос, в ngsw-config.json в разделе ресурсов. Это кэшировало запрос в кэш рабочего сервиса. Кеш сервисных работников может быть открыт с помощью caches.open('ngsw:db:${name}')
но я не должен был этого делать.
I created a web worker file inside the assets folder
The XHR request was made in it.
When a XHR was made the service worker automatically picked up the cache
So I did not have to use any alternate methods of cache access.
Sworkers was automatically served the XHR request from the cache.
Вот как я этого добился. Я создал сервис на английском языке для сервисного работника:
@Injectable({
providedIn: 'root'
})
export class WebworkerService {
myWorker: any;
constructor() {
this.myWorker = new Worker('/assets/web-worker.js');
this.myWorker.onmessage = function(data) {
console.log(data);
}
}
}
Затем я создал web-worker.js
файл в папке активов:
var ajax = function() {
var prom = new Promise(function(resolve, reject){
if (!!XMLHttpRequest) {
var xhttp = new XMLHttpRequest();
xhttp.onload = function () {
if (this.readyState == 4 && this.status == 200) {
resolve(this.responseText);
}
};
xhttp.open("GET", "/assets/test.md", true);
xhttp.send();
}
});
return prom;
}
async function test (e) {
var workerResult, xhrData;
try {
xhrData = await ajax();
workerResult = xhrData; // Some calculation or activity here
postMessage({res: workerResult});
} catch(err) {
postMessage({err: 'Failed'});
}
}
onmessage = function (e) {
test(e);
};
мой ngsw-config.json
был раздел активов, который кэшировал assets / test.md:
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**"
]
}
}
Из компонента, например, app.component.ts, я запустил postMessage()
@Component({
selector: 'app-root',
template:`
<h1 (click)="myHttp()">
Some Client Event
</h1>
`,
styleUrls: ['./app.component.css'],
providers: []
})
export class AppComponent {
constructor(private _ww: WebworkerService) { }
myHttp() {
this._ww.myWorker.postMessage('Test');
}
}
Это заставляет web-worker.js запускать запрос XHR. Хотя я ожидал, что мне придется использовать API доступа к кешу, это было не так. Работник сервиса автоматически подает файл из кеша (что фантастично). Однако, если есть необходимость доступа к кешу, я обнаружил, что это можно сделать с помощью API кеша здесь: https://developer.mozilla.org/en-US/docs/Web/API/Cache
Я уверен, что все может быть улучшено, а структурирование файлов может стать более чистым в соответствии с лучшими практиками. Если вы найдете лучшее решение, пожалуйста, оставьте ответ, чтобы он помог всем.
1 ответ
Да, это может сделать сервисный работник, но:
Браузер может прекратить работу сервисного работника, если он считает, что сервисный работник завершил работу. Поэтому не забудьте обернуть все внутри обещания и использовать event.waitUntil, чтобы убедиться, что процесс не завершен до его завершения.
self.addEventListener ("message", function (event) {event.waitUntil (test (event));});
Работник сервиса работает в одном потоке, поэтому, если вы выполняете длинную синхронную операцию, вы замедляете каждый запрос вашей страницы. Сервисные работники не предназначены для длительного расчета.
Да, разделяемые работники могут получить доступ к API кеша. Вы можете получить к нему доступ так же, как и от работника службы, используя глобальные переменные кэши
caches.open(cacheName).then(function(cache) {
cache.match("...")
});